summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp61
-rw-r--r--Android.mk5
-rw-r--r--apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java2
-rw-r--r--apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java2
-rw-r--r--api/current.txt612
-rw-r--r--api/removed.txt2
-rw-r--r--api/system-current.txt66
-rw-r--r--api/test-current.txt40
-rw-r--r--cmds/bootanimation/bootanim.rc1
-rw-r--r--cmds/idmap2/Android.bp2
-rw-r--r--cmds/idmap2/idmap2/Create.cpp2
-rw-r--r--cmds/idmap2/idmap2/Dump.cpp2
-rw-r--r--cmds/idmap2/idmap2/Lookup.cpp2
-rw-r--r--cmds/idmap2/idmap2/Main.cpp2
-rw-r--r--cmds/idmap2/idmap2/Scan.cpp3
-rw-r--r--cmds/idmap2/idmap2/Verify.cpp2
-rw-r--r--cmds/idmap2/idmap2d/Idmap2Service.cpp14
-rw-r--r--cmds/idmap2/include/idmap2/SysTrace.h87
-rw-r--r--cmds/idmap2/libidmap2/Idmap.cpp3
-rw-r--r--cmds/statsd/Android.bp3
-rw-r--r--cmds/statsd/benchmark/metric_util.cpp5
-rw-r--r--cmds/statsd/src/StatsLogProcessor.cpp86
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h16
-rw-r--r--cmds/statsd/src/StatsService.cpp170
-rw-r--r--cmds/statsd/src/StatsService.h36
-rw-r--r--cmds/statsd/src/atoms.proto81
-rw-r--r--cmds/statsd/src/config/ConfigManager.cpp12
-rw-r--r--cmds/statsd/src/external/StatsCallbackPuller.cpp61
-rw-r--r--cmds/statsd/src/external/StatsCallbackPuller.h38
-rw-r--r--cmds/statsd/src/external/StatsPuller.cpp2
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.cpp33
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.h8
-rw-r--r--cmds/statsd/src/external/TrainInfoPuller.cpp53
-rw-r--r--cmds/statsd/src/external/TrainInfoPuller.h (renamed from media/java/android/media/session/MediaSessionProviderService.java)31
-rw-r--r--cmds/statsd/src/guardrail/StatsdStats.cpp73
-rw-r--r--cmds/statsd/src/guardrail/StatsdStats.h43
-rw-r--r--cmds/statsd/src/logd/LogEvent.cpp31
-rw-r--r--cmds/statsd/src/logd/LogEvent.h13
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.cpp2
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.cpp7
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.h1
-rw-r--r--cmds/statsd/src/metrics/EventMetricProducer.cpp2
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.cpp10
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.cpp42
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.h25
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.cpp14
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h16
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.cpp35
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.h2
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.cpp2
-rw-r--r--cmds/statsd/src/stats_log.proto5
-rw-r--r--cmds/statsd/src/stats_log_util.cpp13
-rw-r--r--cmds/statsd/src/stats_log_util.h2
-rw-r--r--cmds/statsd/src/statsd_config.proto7
-rw-r--r--cmds/statsd/src/storage/StorageManager.cpp68
-rw-r--r--cmds/statsd/src/storage/StorageManager.h17
-rw-r--r--cmds/statsd/statsd.rc1
-rw-r--r--cmds/statsd/tests/StatsLogProcessor_test.cpp234
-rw-r--r--cmds/statsd/tests/UidMap_test.cpp3
-rw-r--r--cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp81
-rw-r--r--cmds/statsd/tests/guardrail/StatsdStats_test.cpp62
-rw-r--r--cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp46
-rw-r--r--cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp59
-rw-r--r--cmds/statsd/tests/statsd_test_util.cpp5
-rw-r--r--cmds/statsd/tests/storage/StorageManager_test.cpp52
-rw-r--r--config/hiddenapi-greylist.txt4
-rw-r--r--core/java/android/accessibilityservice/OWNERS3
-rw-r--r--core/java/android/app/Activity.java3
-rw-r--r--core/java/android/app/ActivityManager.java36
-rw-r--r--core/java/android/app/AppOpsManager.java1
-rw-r--r--core/java/android/app/ContextImpl.java21
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl16
-rw-r--r--core/java/android/app/KeyguardManager.java2
-rw-r--r--core/java/android/app/LoadedApk.java10
-rw-r--r--core/java/android/app/StatsManager.java34
-rw-r--r--core/java/android/app/SystemServiceRegistry.java8
-rw-r--r--core/java/android/app/TaskInfo.java9
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java60
-rw-r--r--core/java/android/app/role/RoleManager.java50
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java17
-rw-r--r--core/java/android/content/ContentResolver.java4
-rw-r--r--core/java/android/content/Intent.java45
-rw-r--r--core/java/android/content/pm/ActivityInfo.java10
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java13
-rw-r--r--core/java/android/content/pm/PackageInstaller.java9
-rw-r--r--core/java/android/content/pm/PackageManager.java27
-rw-r--r--core/java/android/content/pm/PackageManagerInternal.java31
-rw-r--r--core/java/android/content/pm/PackageParser.java20
-rw-r--r--core/java/android/content/pm/ShortcutInfo.java4
-rw-r--r--core/java/android/content/res/AssetManager.java14
-rw-r--r--core/java/android/debug/AdbManagerInternal.java12
-rw-r--r--core/java/android/hardware/biometrics/BiometricConstants.java8
-rw-r--r--core/java/android/hardware/biometrics/BiometricFaceConstants.java8
-rw-r--r--core/java/android/hardware/biometrics/BiometricFingerprintConstants.java9
-rw-r--r--core/java/android/hardware/biometrics/BiometricPrompt.java23
-rw-r--r--core/java/android/hardware/biometrics/IBiometricService.aidl2
-rw-r--r--core/java/android/hardware/display/ColorDisplayManager.java19
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java32
-rw-r--r--core/java/android/hardware/display/IColorDisplayManager.aidl1
-rw-r--r--core/java/android/net/ConnectivityManager.java13
-rw-r--r--core/java/android/net/INetworkMonitorCallbacks.aidl2
-rw-r--r--core/java/android/net/InterfaceConfiguration.java5
-rw-r--r--core/java/android/net/NetworkCapabilities.java14
-rw-r--r--core/java/android/net/NetworkPolicyManager.java10
-rw-r--r--core/java/android/net/NetworkStack.java33
-rw-r--r--core/java/android/os/AsyncTask.java52
-rw-r--r--core/java/android/os/BatteryStats.java65
-rw-r--r--core/java/android/os/FileUtils.java6
-rw-r--r--core/java/android/os/GraphicsEnvironment.java184
-rw-r--r--core/java/android/os/IStatsCompanionService.aidl6
-rw-r--r--core/java/android/os/IStatsManager.aidl39
-rw-r--r--core/java/android/os/IStatsPullerCallback.aidl35
-rw-r--r--core/java/android/os/LocaleList.java10
-rw-r--r--core/java/android/os/PowerManager.java2
-rw-r--r--core/java/android/os/RecoverySystem.java4
-rw-r--r--core/java/android/os/StatsLogEventWrapper.java78
-rw-r--r--core/java/android/os/connectivity/CellularBatteryStats.java13
-rw-r--r--core/java/android/os/connectivity/WifiBatteryStats.java13
-rw-r--r--core/java/android/os/storage/StorageManager.java2
-rw-r--r--core/java/android/provider/DeviceConfig.java91
-rw-r--r--core/java/android/provider/DocumentsContract.java4
-rw-r--r--core/java/android/provider/MediaStore.java48
-rw-r--r--core/java/android/provider/Settings.java62
-rw-r--r--core/java/android/service/autofill/augmented/AugmentedAutofillService.java2
-rw-r--r--core/java/android/service/autofill/augmented/FillCallback.java2
-rw-r--r--core/java/android/service/autofill/augmented/FillController.java4
-rw-r--r--core/java/android/service/autofill/augmented/FillRequest.java2
-rw-r--r--core/java/android/service/autofill/augmented/FillResponse.java4
-rw-r--r--core/java/android/service/autofill/augmented/FillWindow.java4
-rw-r--r--core/java/android/service/autofill/augmented/PresentationParams.java122
-rw-r--r--core/java/android/service/contentcapture/ContentCaptureEventsRequest.java3
-rw-r--r--core/java/android/service/contentcapture/ContentCaptureService.java6
-rw-r--r--core/java/android/service/euicc/EuiccService.java7
-rw-r--r--core/java/android/service/notification/StatusBarNotification.java7
-rw-r--r--core/java/android/service/textclassifier/TEST_MAPPING7
-rw-r--r--core/java/android/text/style/DynamicDrawableSpan.java9
-rw-r--r--core/java/android/util/MathUtils.java46
-rw-r--r--core/java/android/util/StatsLog.java95
-rw-r--r--core/java/android/view/AccessibilityInteractionController.java14
-rw-r--r--core/java/android/view/Choreographer.java2
-rw-r--r--core/java/android/view/Display.java7
-rw-r--r--core/java/android/view/DisplayAddress.java174
-rw-r--r--core/java/android/view/DisplayInfo.java9
-rw-r--r--core/java/android/view/GhostView.java5
-rw-r--r--core/java/android/view/InputDevice.java6
-rw-r--r--core/java/android/view/LayoutInflater.java33
-rw-r--r--core/java/android/view/MotionEvent.java3
-rw-r--r--core/java/android/view/RenderNodeAnimator.java7
-rw-r--r--core/java/android/view/ScaleGestureDetector.java10
-rw-r--r--core/java/android/view/ThreadedRenderer.java6
-rw-r--r--core/java/android/view/View.java163
-rw-r--r--core/java/android/view/ViewConfiguration.java30
-rw-r--r--core/java/android/view/ViewGroup.java18
-rw-r--r--core/java/android/view/ViewRootImpl.java32
-rw-r--r--core/java/android/view/ViewStub.java3
-rw-r--r--core/java/android/view/WindowManagerGlobal.java2
-rw-r--r--core/java/android/view/accessibility/AccessibilityManager.java2
-rw-r--r--core/java/android/view/accessibility/OWNERS3
-rw-r--r--core/java/android/view/animation/Animation.java56
-rw-r--r--core/java/android/view/autofill/AutofillManager.java38
-rw-r--r--core/java/android/view/contentcapture/ChildContentCaptureSession.java30
-rw-r--r--core/java/android/view/contentcapture/ContentCaptureEvent.java35
-rw-r--r--core/java/android/view/contentcapture/ContentCaptureManager.java19
-rw-r--r--core/java/android/view/contentcapture/ContentCaptureSession.java41
-rw-r--r--core/java/android/view/contentcapture/MainContentCaptureSession.java17
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java2
-rw-r--r--core/java/android/view/textclassifier/ConversationAction.java3
-rw-r--r--core/java/android/view/textclassifier/TEST_MAPPING15
-rw-r--r--core/java/android/view/textclassifier/TextClassificationConstants.java1
-rw-r--r--core/java/android/webkit/OWNERS1
-rw-r--r--core/java/android/webkit/WebView.java24
-rw-r--r--core/java/android/widget/AbsListView.java8
-rw-r--r--core/java/android/widget/AbsSeekBar.java2
-rw-r--r--core/java/android/widget/AbsSpinner.java2
-rw-r--r--core/java/android/widget/ActivityChooserView.java2
-rw-r--r--core/java/android/widget/AdapterViewAnimator.java3
-rw-r--r--core/java/android/widget/AdapterViewFlipper.java2
-rw-r--r--core/java/android/widget/AnalogClock.java2
-rw-r--r--core/java/android/widget/AutoCompleteTextView.java84
-rw-r--r--core/java/android/widget/CalendarView.java2
-rw-r--r--core/java/android/widget/CheckedTextView.java2
-rw-r--r--core/java/android/widget/Chronometer.java2
-rw-r--r--core/java/android/widget/CompoundButton.java2
-rw-r--r--core/java/android/widget/DatePicker.java2
-rw-r--r--core/java/android/widget/DayPickerView.java2
-rw-r--r--core/java/android/widget/Editor.java6
-rw-r--r--core/java/android/widget/ExpandableListView.java2
-rw-r--r--core/java/android/widget/FrameLayout.java2
-rw-r--r--core/java/android/widget/Gallery.java2
-rw-r--r--core/java/android/widget/GridLayout.java2
-rw-r--r--core/java/android/widget/GridView.java2
-rw-r--r--core/java/android/widget/HorizontalScrollView.java116
-rw-r--r--core/java/android/widget/ImageView.java4
-rw-r--r--core/java/android/widget/LinearLayout.java2
-rw-r--r--core/java/android/widget/ListPopupWindow.java21
-rw-r--r--core/java/android/widget/ListView.java2
-rw-r--r--core/java/android/widget/NumberPicker.java44
-rw-r--r--core/java/android/widget/PopupWindow.java4
-rw-r--r--core/java/android/widget/ProgressBar.java20
-rw-r--r--core/java/android/widget/RadialTimePickerView.java2
-rw-r--r--core/java/android/widget/RadioGroup.java2
-rw-r--r--core/java/android/widget/RatingBar.java2
-rw-r--r--core/java/android/widget/RelativeLayout.java2
-rw-r--r--core/java/android/widget/ScrollBarDrawable.java46
-rw-r--r--core/java/android/widget/ScrollView.java125
-rw-r--r--core/java/android/widget/SearchView.java2
-rw-r--r--core/java/android/widget/SlidingDrawer.java2
-rw-r--r--core/java/android/widget/Spinner.java2
-rw-r--r--core/java/android/widget/StackView.java2
-rw-r--r--core/java/android/widget/Switch.java2
-rw-r--r--core/java/android/widget/TabHost.java2
-rw-r--r--core/java/android/widget/TabWidget.java2
-rw-r--r--core/java/android/widget/TextClock.java12
-rw-r--r--core/java/android/widget/TextView.java2
-rw-r--r--core/java/android/widget/TimePicker.java2
-rw-r--r--core/java/android/widget/ToggleButton.java2
-rw-r--r--core/java/android/widget/Toolbar.java2
-rw-r--r--core/java/android/widget/TwoLineListItem.java2
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java197
-rw-r--r--core/java/com/android/internal/colorextraction/ColorExtractor.java14
-rw-r--r--core/java/com/android/internal/colorextraction/types/Tonal.java24
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java185
-rw-r--r--core/java/com/android/internal/os/BinderCallsStats.java37
-rw-r--r--core/java/com/android/internal/os/ChildZygoteInit.java2
-rw-r--r--core/java/com/android/internal/os/KernelCpuThreadReader.java33
-rw-r--r--core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java13
-rw-r--r--core/java/com/android/internal/os/LooperStats.java10
-rw-r--r--core/java/com/android/internal/os/RailStats.java147
-rw-r--r--core/java/com/android/internal/util/ImageUtils.java62
-rw-r--r--core/jni/Android.bp4
-rwxr-xr-xcore/jni/android/graphics/Bitmap.cpp83
-rw-r--r--core/jni/android/graphics/BitmapFactory.cpp2
-rw-r--r--core/jni/android/graphics/BitmapRegionDecoder.cpp2
-rw-r--r--core/jni/android/graphics/Graphics.cpp127
-rw-r--r--core/jni/android/graphics/GraphicsJNI.h8
-rw-r--r--core/jni/android/graphics/ImageDecoder.cpp4
-rw-r--r--core/jni/android_opengl_EGL14.cpp14
-rw-r--r--core/jni/android_os_GraphicsEnvironment.cpp6
-rw-r--r--core/jni/android_util_AssetManager.cpp60
-rw-r--r--core/jni/android_view_ThreadedRenderer.cpp80
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp70
-rwxr-xr-xcore/jni/runtime_native_boot-flags-test.sh244
-rw-r--r--core/proto/android/app/settings_enums.proto17
-rw-r--r--core/proto/android/bluetooth/enums.proto6
-rw-r--r--core/proto/android/hardware/biometrics/enums.proto12
-rw-r--r--core/proto/android/hardware/sensor/assist/enums.proto34
-rw-r--r--core/proto/android/os/batterystats.proto4
-rw-r--r--core/proto/android/providers/settings/global.proto5
-rw-r--r--core/proto/android/server/connectivity/Android.bp25
-rw-r--r--core/res/AndroidManifest.xml8
-rw-r--r--core/res/res/drawable/bottomsheet_background.xml4
-rw-r--r--core/res/res/drawable/ic_action_open.xml24
-rw-r--r--core/res/res/drawable/ic_file_copy.xml24
-rw-r--r--core/res/res/drawable/ic_qs_night_display_on.xml23
-rw-r--r--core/res/res/layout/chooser_grid.xml59
-rw-r--r--core/res/res/layout/notification_template_material_media.xml2
-rw-r--r--core/res/res/values/attrs_manifest.xml9
-rw-r--r--core/res/res/values/config.xml39
-rw-r--r--core/res/res/values/public.xml6
-rw-r--r--core/res/res/values/strings.xml11
-rw-r--r--core/res/res/values/styles_device_defaults.xml4
-rw-r--r--core/res/res/values/symbols.xml13
-rw-r--r--core/tests/coretests/src/android/content/pm/PackageParserTest.java66
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java4
-rw-r--r--core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java41
-rw-r--r--core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java5
-rw-r--r--core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java3
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java6
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java3
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java82
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java8
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java67
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java57
-rw-r--r--core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java28
-rw-r--r--data/etc/privapp-permissions-platform.xml15
-rw-r--r--graphics/java/android/graphics/Bitmap.java138
-rw-r--r--graphics/java/android/graphics/BitmapFactory.java9
-rw-r--r--graphics/java/android/graphics/ColorSpace.java2
-rw-r--r--graphics/java/android/graphics/HardwareRenderer.java234
-rw-r--r--graphics/java/android/graphics/ImageDecoder.java9
-rw-r--r--graphics/java/android/graphics/Typeface.java12
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java7
-rw-r--r--graphics/java/android/graphics/drawable/ColorStateListDrawable.java18
-rw-r--r--graphics/java/android/graphics/drawable/GradientDrawable.java171
-rw-r--r--keystore/java/android/security/KeyChain.java33
-rw-r--r--libs/androidfw/AssetManager2.cpp21
-rw-r--r--libs/androidfw/LoadedArsc.cpp7
-rw-r--r--libs/androidfw/include/androidfw/AssetManager2.h3
-rw-r--r--libs/androidfw/include/androidfw/LoadedArsc.h6
-rw-r--r--libs/androidfw/tests/AssetManager2_test.cpp20
-rw-r--r--libs/androidfw/tests/LoadedArsc_test.cpp20
-rw-r--r--libs/hwui/FrameMetricsObserver.h2
-rw-r--r--libs/hwui/Readback.cpp2
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp5
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp26
-rw-r--r--libs/hwui/renderthread/RenderThread.h3
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp69
-rw-r--r--libs/hwui/renderthread/VulkanManager.h23
-rw-r--r--libs/hwui/tests/common/TestUtils.cpp2
-rw-r--r--libs/input/PointerController.cpp124
-rw-r--r--libs/input/PointerController.h14
-rw-r--r--location/java/android/location/GnssMeasurement.java397
-rw-r--r--location/java/android/location/LocationRequest.java29
-rw-r--r--location/java/com/android/internal/location/ProviderRequest.java11
-rw-r--r--location/lib/api/current.txt3
-rw-r--r--location/lib/java/com/android/location/provider/LocationRequestUnbundled.java9
-rw-r--r--location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java6
-rw-r--r--media/Android.bp13
-rw-r--r--media/apex/java/android/media/MediaController2.java2
-rw-r--r--media/apex/java/android/media/MediaPlayer2.java2
-rw-r--r--media/java/android/media/IRingtonePlayer.aidl3
-rw-r--r--media/java/android/media/MediaCodecInfo.java104
-rw-r--r--media/java/android/media/MediaPlayer.java21
-rw-r--r--media/java/android/media/Ringtone.java3
-rw-r--r--media/java/android/media/VolumeShaper.aidl (renamed from core/java/android/os/ParcelFileDescriptor.aidl)25
-rw-r--r--media/java/android/media/session/ControllerLink.java27
-rw-r--r--media/java/android/media/session/ISessionCallback.aidl2
-rw-r--r--media/java/android/media/session/ISessionController.aidl1
-rw-r--r--media/java/android/media/session/MediaController.java13
-rw-r--r--media/java/android/media/session/MediaSession.java13
-rw-r--r--media/java/android/media/session/MediaSessionEngine.java27
-rw-r--r--media/java/android/media/session/SessionCallbackLink.java36
-rw-r--r--media/jni/soundpool/SoundPool.cpp9
-rw-r--r--media/native/midi/Android.bp8
-rw-r--r--media/native/midi/amidi.cpp (renamed from media/native/midi/midi.cpp)4
-rw-r--r--media/native/midi/amidi_internal.h (renamed from media/native/midi/midi_internal.h)6
-rw-r--r--media/native/midi/include/amidi/AMidi.h (renamed from media/native/midi/include/midi.h)55
-rw-r--r--media/native/midi/include/amidi/NOTICE (renamed from media/native/midi/include/NOTICE)0
-rw-r--r--media/packages/MediaCore/Android.bp.bak21
-rw-r--r--media/packages/MediaCore/AndroidManifest.xml32
-rw-r--r--media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java37
-rw-r--r--media/proto/jarjar-rules.txt2
-rw-r--r--native/android/libandroid.map.txt2
-rw-r--r--native/android/surface_control.cpp14
-rw-r--r--packages/CaptivePortalLogin/res/values-gl/strings.xml2
-rw-r--r--packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java1
-rw-r--r--packages/CarSystemUI/res/values/colors_car.xml2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java24
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java21
-rw-r--r--packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java1
-rw-r--r--packages/DynamicAndroidInstallationService/Android.mk19
-rw-r--r--packages/DynamicAndroidInstallationService/AndroidManifest.xml47
-rw-r--r--packages/DynamicAndroidInstallationService/MODULE_LICENSE_APACHE20
-rw-r--r--packages/DynamicAndroidInstallationService/NOTICE190
-rw-r--r--packages/DynamicAndroidInstallationService/res/drawable/ic_system_update_googblue_24dp.xml9
-rw-r--r--packages/DynamicAndroidInstallationService/res/values/strings.xml33
-rw-r--r--packages/DynamicAndroidInstallationService/src/com/android/dynandroid/BootCompletedReceiver.java50
-rw-r--r--packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java483
-rw-r--r--packages/DynamicAndroidInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java205
-rw-r--r--packages/DynamicAndroidInstallationService/src/com/android/dynandroid/VerificationActivity.java104
-rw-r--r--packages/ExtServices/src/android/ext/services/notification/Assistant.java4
-rw-r--r--packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java228
-rw-r--r--packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java124
-rw-r--r--packages/NetworkStack/AndroidManifest.xml5
-rw-r--r--packages/NetworkStack/src/android/net/ip/IpClient.java10
-rw-r--r--packages/NetworkStack/src/com/android/server/NetworkStackService.java3
-rw-r--r--packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java65
-rw-r--r--packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java2
-rw-r--r--packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java2
-rw-r--r--packages/SettingsLib/Android.bp1
-rw-r--r--packages/SettingsLib/AppPreference/res/layout/preference_app.xml6
-rw-r--r--packages/SettingsLib/EntityHeaderWidgets/res/layout/app_view.xml2
-rw-r--r--packages/SettingsLib/ProgressBar/Android.bp9
-rw-r--r--packages/SettingsLib/ProgressBar/AndroidManifest.xml23
-rw-r--r--packages/SettingsLib/ProgressBar/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml28
-rw-r--r--packages/SettingsLib/ProgressBar/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml53
-rw-r--r--packages/SettingsLib/ProgressBar/res/layout/progress_header.xml34
-rw-r--r--packages/SettingsLib/ProgressBar/res/values/styles.xml (renamed from media/packages/MediaCore/res/values/strings.xml)15
-rw-r--r--packages/SettingsLib/res/drawable/ic_info_outline_24.xml27
-rw-r--r--packages/SettingsLib/res/drawable/ic_system_update.xml25
-rw-r--r--packages/SettingsLib/res/values/strings.xml3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java34
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java7
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java7
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java132
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java235
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java36
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java6
-rw-r--r--packages/Shell/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java9
-rw-r--r--packages/SystemUI/res-keyguard/layout/bubble_clock.xml16
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml11
-rw-r--r--packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml16
-rw-r--r--packages/SystemUI/res-keyguard/layout/text_clock.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values-af/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-am/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-ar/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-as/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-az/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-be/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-bg/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-bn/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-bs/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-ca/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-cs/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-da/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-de/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-el/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-en-rAU/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-en-rCA/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-en-rGB/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-en-rIN/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-en-rXC/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-es-rUS/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-es/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-et/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-eu/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-fa/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-fi/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-fr/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-gl/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-gu/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-hi/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-hr/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-hu/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-hy/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-in/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-is/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-it/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-iw/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-ja/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-ka/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-kk/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-km/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-kn/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-ko/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-ky/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-lo/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-lt/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-lv/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-mk/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-ml/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-mn/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-mr/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-ms/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-my/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-nb/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-ne/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-nl/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-or/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-pa/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-pl/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-pt/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-ro/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-ru/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-si/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-sk/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-sl/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-sq/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-sr/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-sv/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-sw/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-ta/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-te/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-th/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-tl/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-tr/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-uk/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-ur/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-uz/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-vi/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-zu/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values/dimens.xml12
-rw-r--r--packages/SystemUI/res-keyguard/values/strings.xml3
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml21
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml13
-rw-r--r--packages/SystemUI/res/drawable/ic_signal_airplane.xml22
-rw-r--r--packages/SystemUI/res/drawable/privacy_chip_bg.xml3
-rw-r--r--packages/SystemUI/res/drawable/rounded_bg.xml4
-rw-r--r--packages/SystemUI/res/drawable/rounded_bg_bottom.xml2
-rw-r--r--packages/SystemUI/res/drawable/rounded_bg_bottom_background.xml4
-rw-r--r--packages/SystemUI/res/drawable/rounded_bg_full.xml8
-rw-r--r--packages/SystemUI/res/drawable/rounded_full_bg_bottom.xml4
-rw-r--r--packages/SystemUI/res/layout-land/global_actions_grid.xml80
-rw-r--r--packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml82
-rw-r--r--packages/SystemUI/res/layout/global_actions_grid.xml17
-rw-r--r--packages/SystemUI/res/layout/global_actions_grid_item.xml2
-rw-r--r--packages/SystemUI/res/layout/notification_info.xml119
-rw-r--r--packages/SystemUI/res/layout/ongoing_privacy_chip.xml19
-rw-r--r--packages/SystemUI/res/values-af/strings.xml11
-rw-r--r--packages/SystemUI/res/values-am/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml11
-rw-r--r--packages/SystemUI/res/values-as/strings.xml6
-rw-r--r--packages/SystemUI/res/values-az/strings.xml11
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml11
-rw-r--r--packages/SystemUI/res/values-be/strings.xml6
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml11
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml6
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml6
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml6
-rw-r--r--packages/SystemUI/res/values-da/strings.xml11
-rw-r--r--packages/SystemUI/res/values-de/strings.xml13
-rw-r--r--packages/SystemUI/res/values-el/strings.xml11
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml11
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml11
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml11
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml11
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml11
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml11
-rw-r--r--packages/SystemUI/res/values-es/strings.xml6
-rw-r--r--packages/SystemUI/res/values-et/strings.xml11
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml11
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml11
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml11
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml6
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml6
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml11
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml6
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml6
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml11
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml11
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml6
-rw-r--r--packages/SystemUI/res/values-in/strings.xml11
-rw-r--r--packages/SystemUI/res/values-is/strings.xml11
-rw-r--r--packages/SystemUI/res/values-it/strings.xml11
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml10
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml11
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml6
-rw-r--r--packages/SystemUI/res/values-km/strings.xml6
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml6
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml6
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml11
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml11
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml6
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml11
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml6
-rw-r--r--packages/SystemUI/res/values-my/strings.xml13
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml6
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml13
-rw-r--r--packages/SystemUI/res/values-or/strings.xml6
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml6
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml11
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml11
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml11
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml11
-rw-r--r--packages/SystemUI/res/values-si/strings.xml11
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml11
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml11
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml6
-rw-r--r--packages/SystemUI/res/values-te/strings.xml6
-rw-r--r--packages/SystemUI/res/values-th/strings.xml11
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml11
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml6
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml11
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml11
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml11
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml6
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml11
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml11
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml11
-rw-r--r--packages/SystemUI/res/values/dimens.xml10
-rw-r--r--packages/SystemUI/res/values/strings.xml14
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl45
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/InputChannelCompat.java13
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java28
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java52
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java128
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java61
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java90
-rw-r--r--packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java12
-rw-r--r--packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java6
-rw-r--r--packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java117
-rw-r--r--packages/SystemUI/src/com/android/keyguard/clock/DefaultClockSupplier.java101
-rw-r--r--packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java10
-rw-r--r--packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java48
-rw-r--r--packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java8
-rw-r--r--packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java13
-rw-r--r--packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/DependencyBinder.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/MultiListLayout.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistManager.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java141
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java70
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java287
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java246
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java115
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java104
-rw-r--r--packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeReceiver.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerUI.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt63
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt45
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java66
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java73
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java75
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/clock/DefaultClockSupplierTest.java132
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt39
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java186
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java39
-rw-r--r--proto/src/metrics_constants/metrics_constants.proto17
-rw-r--r--proto/src/wifi.proto38
-rw-r--r--sax/tests/saxtests/Android.bp11
-rw-r--r--sax/tests/saxtests/Android.mk16
-rw-r--r--services/accessibility/OWNERS3
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java38
-rw-r--r--services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java14
-rw-r--r--services/backup/java/com/android/server/backup/encryption/chunk/ChunkListingMap.java (renamed from services/backup/java/com/android/server/backup/encryption/chunk/ChunkListing.java)15
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java73
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java3
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java3
-rw-r--r--services/core/java/com/android/server/AlarmManagerInternal.java2
-rw-r--r--services/core/java/com/android/server/AlarmManagerService.java11
-rw-r--r--services/core/java/com/android/server/BinderCallsStatsService.java8
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java7
-rw-r--r--services/core/java/com/android/server/DeviceIdleController.java185
-rw-r--r--services/core/java/com/android/server/ExtconUEventObserver.java57
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java351
-rw-r--r--services/core/java/com/android/server/LooperStatsService.java13
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java38
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java4
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java113
-rw-r--r--services/core/java/com/android/server/WiredAccessoryManager.java155
-rw-r--r--services/core/java/com/android/server/adb/AdbDebuggingManager.java80
-rw-r--r--services/core/java/com/android/server/adb/AdbService.java11
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java5
-rw-r--r--services/core/java/com/android/server/am/BatteryExternalStatsWorker.java4
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java24
-rw-r--r--services/core/java/com/android/server/am/BroadcastDispatcher.java76
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java24
-rw-r--r--services/core/java/com/android/server/am/CoreSettingsObserver.java3
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java4
-rw-r--r--services/core/java/com/android/server/am/UserController.java3
-rw-r--r--services/core/java/com/android/server/appbinding/AppBindingService.java38
-rw-r--r--services/core/java/com/android/server/appbinding/finders/CarrierMessagingClientServiceFinder.java37
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java61
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java171
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java23
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricServiceBase.java3
-rw-r--r--services/core/java/com/android/server/biometrics/LoggableMonitor.java4
-rw-r--r--services/core/java/com/android/server/biometrics/face/FaceService.java5
-rw-r--r--services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java5
-rw-r--r--services/core/java/com/android/server/connectivity/Tethering.java15
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java63
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java8
-rw-r--r--services/core/java/com/android/server/display/ColorDisplayService.java113
-rw-r--r--services/core/java/com/android/server/display/DisplayDevice.java9
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceInfo.java3
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java2
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java2
-rw-r--r--services/core/java/com/android/server/display/WifiDisplayAdapter.java11
-rw-r--r--services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java23
-rw-r--r--services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java7
-rw-r--r--services/core/java/com/android/server/gpu/GpuService.java101
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java2
-rw-r--r--services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java2
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java13
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java42
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerService.java2
-rw-r--r--services/core/java/com/android/server/job/controllers/StateController.java1
-rw-r--r--services/core/java/com/android/server/job/controllers/TimeController.java59
-rw-r--r--services/core/java/com/android/server/location/GnssConfiguration.java2
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java6
-rw-r--r--services/core/java/com/android/server/location/RemoteListenerHelper.java73
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java7
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java78
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java16
-rw-r--r--services/core/java/com/android/server/media/MediaSessionServiceImpl.java26
-rw-r--r--services/core/java/com/android/server/net/LockdownVpnTracker.java8
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyLogger.java10
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java10
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerService.java542
-rw-r--r--services/core/java/com/android/server/pm/ApexManager.java221
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java8
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java248
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java5
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java46
-rw-r--r--services/core/java/com/android/server/pm/ShortcutParser.java3
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java92
-rw-r--r--services/core/java/com/android/server/pm/UserRestrictionsUtils.java4
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java4
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java60
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java4
-rw-r--r--services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java66
-rw-r--r--services/core/java/com/android/server/power/AttentionDetector.java5
-rw-r--r--services/core/java/com/android/server/role/RoleManagerService.java33
-rw-r--r--services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java39
-rw-r--r--services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java49
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java41
-rw-r--r--services/core/java/com/android/server/testharness/TestHarnessModeService.java113
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java228
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java13
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java65
-rw-r--r--services/core/java/com/android/server/wm/AppWindowThumbnail.java2
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java177
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java10
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java22
-rw-r--r--services/core/java/com/android/server/wm/InputManagerCallback.java11
-rw-r--r--services/core/java/com/android/server/wm/Letterbox.java127
-rw-r--r--services/core/java/com/android/server/wm/RootActivityContainer.java5
-rw-r--r--services/core/java/com/android/server/wm/SurfaceAnimator.java8
-rw-r--r--services/core/java/com/android/server/wm/TaskRecord.java44
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java42
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java99
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowTracing.java108
-rw-r--r--services/core/jni/com_android_server_am_BatteryStatsService.cpp119
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp13
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp5
-rw-r--r--services/core/jni/com_android_server_security_VerityUtils.cpp2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java37
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java17
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/NonAbUpdateInstaller.java4
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/Owners.java19
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java8
-rw-r--r--services/java/com/android/server/SystemServer.java46
-rw-r--r--services/net/Android.bp3
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingMapTest.java (renamed from services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java)64
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java (renamed from services/robotests/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java)0
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java (renamed from services/robotests/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java)0
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java (renamed from services/robotests/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java)0
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java230
-rw-r--r--services/tests/servicestests/AndroidManifest.xml2
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkManagementInternalTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java87
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java9
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java55
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java26
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java79
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java50
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java9
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/KeyguardDisableHandlerTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java35
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java17
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java11
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/utils/CoordinateTransformsTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java94
-rw-r--r--services/usage/java/com/android/server/usage/AppTimeLimitController.java5
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java2
-rw-r--r--telecomm/java/android/telecom/Conference.java2
-rw-r--r--telecomm/java/android/telecom/DefaultDialerManager.java34
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java21
-rw-r--r--telephony/java/android/provider/Telephony.java35
-rw-r--r--telephony/java/android/telephony/AccessNetworkConstants.java8
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java23
-rw-r--r--telephony/java/android/telephony/CarrierRestrictionRules.java122
-rw-r--r--telephony/java/android/telephony/CellIdentityNr.java21
-rw-r--r--telephony/java/android/telephony/CellIdentityTdscdma.java8
-rw-r--r--telephony/java/android/telephony/LocationAccessPolicy.java294
-rw-r--r--telephony/java/android/telephony/NetworkRegistrationState.java59
-rw-r--r--telephony/java/android/telephony/PhoneStateListener.java3
-rw-r--r--telephony/java/android/telephony/ServiceState.java44
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java37
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java101
-rw-r--r--telephony/java/android/telephony/TelephonyScanManager.java13
-rw-r--r--telephony/java/android/telephony/euicc/EuiccManager.java44
-rw-r--r--telephony/java/android/telephony/ims/ImsCallProfile.java31
-rw-r--r--telephony/java/android/telephony/ims/Rcs1To1Thread.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsEvent.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsEventQueryParams.java6
-rw-r--r--telephony/java/android/telephony/ims/RcsEventQueryResult.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsFileTransferCreationParams.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsFileTransferPart.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsGroupThread.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsGroupThreadEvent.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsIncomingMessage.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsManager.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsMessage.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsMessageCreationParams.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsMessageQueryParams.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsMessageQueryResult.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsMessageSnippet.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsMessageStore.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsMessageStoreException.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsOutgoingMessage.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsOutgoingMessageDelivery.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsParticipant.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsParticipantQueryParams.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsParticipantQueryResult.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsQueryContinuationToken.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsThread.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsThreadQueryParams.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsThreadQueryResult.java2
-rw-r--r--telephony/java/com/android/internal/telephony/ISetOpportunisticDataCallback.aidl25
-rwxr-xr-xtelephony/java/com/android/internal/telephony/ISub.aidl7
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl8
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyPermissions.java3
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/BearerData.java50
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/SmsMessage.java5
-rw-r--r--test-runner/Android.mk20
-rw-r--r--test-runner/tests/Android.bp40
-rw-r--r--test-runner/tests/Android.mk39
-rw-r--r--tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java8
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml24
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java76
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/MyLittleTextureView.java87
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java8
-rw-r--r--tests/net/java/com/android/server/connectivity/TetheringTest.java6
-rw-r--r--tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java22
-rw-r--r--tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java79
-rw-r--r--tools/aapt2/Resources.proto10
-rw-r--r--tools/aapt2/link/ManifestFixer.cpp27
-rw-r--r--tools/aapt2/link/ManifestFixer_test.cpp90
-rw-r--r--tools/preload/Android.bp17
-rw-r--r--tools/preload/Android.mk23
-rw-r--r--tools/preload/loadclass/Android.bp4
-rw-r--r--tools/preload/loadclass/Android.mk9
-rw-r--r--tools/stats_log_api_gen/main.cpp26
-rw-r--r--wifi/java/android/net/wifi/WifiInfo.java33
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java12
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkSpecifier.java2
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkSuggestion.java6
-rw-r--r--wifi/java/android/net/wifi/aware/ParcelablePeerHandle.java59
-rw-r--r--wifi/java/android/net/wifi/aware/PeerHandle.java31
-rw-r--r--wifi/java/android/net/wifi/aware/TlvBufferUtils.java125
-rw-r--r--wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java44
-rw-r--r--wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java20
919 files changed, 18984 insertions, 6012 deletions
diff --git a/Android.bp b/Android.bp
index 7bdedc79943d..995fe3e2465e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -602,6 +602,7 @@ java_defaults {
"telephony/java/com/android/internal/telephony/IOnSubscriptionsChangedListener.aidl",
"telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl",
"telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl",
+ "telephony/java/com/android/internal/telephony/ISetOpportunisticDataCallback.aidl",
"telephony/java/com/android/internal/telephony/ISms.aidl",
"telephony/java/com/android/internal/telephony/ISub.aidl",
"telephony/java/com/android/internal/telephony/IOns.aidl",
@@ -741,10 +742,8 @@ java_defaults {
static_libs: [
"apex_aidl_interface-java",
- "networkstack-aidl-interfaces-java",
"framework-protos",
"game-driver-protos",
- "mediaplayer2-protos",
"android.hidl.base-V1.0-java",
"android.hardware.cas-V1.1-java",
"android.hardware.cas-V1.0-java",
@@ -774,7 +773,7 @@ java_defaults {
"android.hardware.vibrator-V1.3-java",
"android.hardware.wifi-V1.0-java-constants",
"networkstack-aidl-interfaces-java",
- "netd_aidl_interface-java",
+ "netd_aidl_parcelables-java",
"devicepolicyprotosnano",
],
@@ -804,6 +803,7 @@ filegroup {
srcs: [
"core/java/android/os/IStatsCompanionService.aidl",
"core/java/android/os/IStatsManager.aidl",
+ "core/java/android/os/IStatsPullerCallback.aidl",
],
}
@@ -1187,58 +1187,21 @@ packages_to_document = [
"org/apache/http/params",
]
-// The since flag (-since N.xml API_LEVEL) is used to add API Level information
-// to the reference documentation. Must be in order of oldest to newest.
-//
-// Conscrypt (com.android.org.conscrypt) is an implementation detail and should
-// not be referenced in the documentation.
-framework_docs_args = "-android -manifest $(location core/res/AndroidManifest.xml) " +
- "-hidePackage com.android.internal " +
- "-hidePackage com.android.internal.util " +
- "-hidePackage com.android.okhttp " +
- "-hidePackage com.android.org.conscrypt " +
- "-hidePackage com.android.server " +
- "-since $(location 1/public/api/android.xml) 1 " +
- "-since $(location 2/public/api/android.xml) 2 " +
- "-since $(location 3/public/api/android.xml) 3 " +
- "-since $(location 4/public/api/android.xml) 4 " +
- "-since $(location 5/public/api/android.xml) 5 " +
- "-since $(location 6/public/api/android.xml) 6 " +
- "-since $(location 7/public/api/android.xml) 7 " +
- "-since $(location 8/public/api/android.xml) 8 " +
- "-since $(location 9/public/api/android.xml) 9 " +
- "-since $(location 10/public/api/android.xml) 10 " +
- "-since $(location 11/public/api/android.xml) 11 " +
- "-since $(location 12/public/api/android.xml) 12 " +
- "-since $(location 13/public/api/android.xml) 13 " +
- "-since $(location 14/public/api/android.txt) 14 " +
- "-since $(location 15/public/api/android.txt) 15 " +
- "-since $(location 16/public/api/android.txt) 16 " +
- "-since $(location 17/public/api/android.txt) 17 " +
- "-since $(location 18/public/api/android.txt) 18 " +
- "-since $(location 19/public/api/android.txt) 19 " +
- "-since $(location 20/public/api/android.txt) 20 " +
- "-since $(location 21/public/api/android.txt) 21 " +
- "-since $(location 22/public/api/android.txt) 22 " +
- "-since $(location 23/public/api/android.txt) 23 " +
- "-since $(location 24/public/api/android.txt) 24 " +
- "-since $(location 25/public/api/android.txt) 25 " +
- "-since $(location 26/public/api/android.txt) 26 " +
- "-since $(location 27/public/api/android.txt) 27 " +
- "-since $(location 28/public/api/android.txt) 28 " +
- "-since $(location api/current.txt) Q " +
- "-werror -lerror -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 " +
- "-overview $(location core/java/overview.html) " +
- // Federate Support Library references against local API file.
- "-federate SupportLib https://developer.android.com " +
- "-federationapi SupportLib $(location current/support-api.txt) "
+// Make the api/current.txt file available for use by modules in other
+// directories.
+filegroup {
+ name: "frameworks-base-api-current.txt",
+ srcs: [
+ "api/current.txt",
+ ],
+}
framework_docs_only_args = " -android -manifest $(location core/res/AndroidManifest.xml) " +
"-werror -lerror -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 " +
"-overview $(location core/java/overview.html) " +
// Federate Support Library references against local API file.
"-federate SupportLib https://developer.android.com " +
- "-federationapi SupportLib $(location current/support-api.txt) "
+ "-federationapi SupportLib $(location :current-support-api) "
framework_docs_only_libs = [
"voip-common",
diff --git a/Android.mk b/Android.mk
index 9c65948f4838..c58f7af1d7d5 100644
--- a/Android.mk
+++ b/Android.mk
@@ -72,10 +72,11 @@ $(OUT_DOCS)/offline-sdk-timestamp: $(OUT_DOCS)/offline-sdk-docs-docs.zip
$(hide) mkdir -p $(OUT_DOCS)/offline-sdk
( unzip -qo $< -d $(OUT_DOCS)/offline-sdk && touch -f $@ ) || exit 1
+.PHONY: docs offline-sdk-docs
+docs offline-sdk-docs: $(OUT_DOCS)/offline-sdk-timestamp
+
# Run this for checkbuild
checkbuild: doc-comment-check-docs
-# Check comment when you are updating the API
-update-api: doc-comment-check-docs
# ==== hiddenapi lists =======================================
ifneq ($(UNSAFE_DISABLE_HIDDENAPI_FLAGS),true)
diff --git a/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java b/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java
index 92348497101e..0c30302d63a3 100644
--- a/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java
@@ -40,7 +40,7 @@ public class KernelCpuThreadReaderPerfTest {
public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private final KernelCpuThreadReader mKernelCpuThreadReader =
- KernelCpuThreadReader.create(8, uid -> 1000 <= uid && uid < 2000);
+ KernelCpuThreadReader.create(8, uid -> 1000 <= uid && uid < 2000, 0);
@Test
public void timeReadCurrentProcessCpuUsage() {
diff --git a/apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java b/apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java
index ec46a75bd807..c506aec624d1 100644
--- a/apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java
+++ b/apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java
@@ -64,7 +64,7 @@ public class TextClassifierPerfTest {
Context context = InstrumentationRegistry.getTargetContext();
TextClassificationManager textClassificationManager =
context.getSystemService(TextClassificationManager.class);
- mTextClassifier = textClassificationManager.getTextClassifier();
+ mTextClassifier = textClassificationManager.getLocalTextClassifier();
}
@Test
diff --git a/api/current.txt b/api/current.txt
index 673d90fc236f..7db19e907be4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -80,7 +80,6 @@ package android {
field public static final String FOREGROUND_SERVICE = "android.permission.FOREGROUND_SERVICE";
field public static final String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
field public static final String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
- field public static final String GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY = "android.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY";
field public static final String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
field @Deprecated public static final String GET_TASKS = "android.permission.GET_TASKS";
field public static final String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
@@ -131,6 +130,7 @@ package android {
field public static final String REQUEST_DELETE_PACKAGES = "android.permission.REQUEST_DELETE_PACKAGES";
field public static final String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
field public static final String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
+ field public static final String REQUEST_SCREEN_LOCK_COMPLEXITY = "android.permission.REQUEST_SCREEN_LOCK_COMPLEXITY";
field @Deprecated public static final String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
field public static final String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
field public static final String SEND_SMS = "android.permission.SEND_SMS";
@@ -6646,7 +6646,7 @@ package android.app.admin {
method @Nullable public CharSequence getOrganizationName(@NonNull android.content.ComponentName);
method public java.util.List<android.telephony.data.ApnSetting> getOverrideApns(@NonNull android.content.ComponentName);
method @NonNull public android.app.admin.DevicePolicyManager getParentProfileInstance(@NonNull android.content.ComponentName);
- method @RequiresPermission(android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY) public int getPasswordComplexity();
+ method @RequiresPermission(android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY) public int getPasswordComplexity();
method public long getPasswordExpiration(@Nullable android.content.ComponentName);
method public long getPasswordExpirationTimeout(@Nullable android.content.ComponentName);
method public int getPasswordHistoryLength(@Nullable android.content.ComponentName);
@@ -6684,7 +6684,7 @@ package android.app.admin {
method public boolean installKeyPair(@Nullable android.content.ComponentName, @NonNull java.security.PrivateKey, @NonNull java.security.cert.Certificate, @NonNull String);
method public boolean installKeyPair(@Nullable android.content.ComponentName, @NonNull java.security.PrivateKey, @NonNull java.security.cert.Certificate[], @NonNull String, boolean);
method public boolean installKeyPair(@Nullable android.content.ComponentName, @NonNull java.security.PrivateKey, @NonNull java.security.cert.Certificate[], @NonNull String, int);
- method public void installSystemUpdate(@NonNull android.content.ComponentName, @NonNull android.net.Uri, @NonNull java.util.concurrent.Executor, @NonNull android.app.admin.DevicePolicyManager.InstallUpdateCallback);
+ method public void installSystemUpdate(@NonNull android.content.ComponentName, @NonNull android.net.Uri, @NonNull java.util.concurrent.Executor, @NonNull android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback);
method public boolean isActivePasswordSufficient();
method public boolean isAdminActive(@NonNull android.content.ComponentName);
method public boolean isAffiliatedUser();
@@ -6840,7 +6840,7 @@ package android.app.admin {
field public static final String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION";
field public static final String EXTRA_DELEGATION_SCOPES = "android.app.extra.DELEGATION_SCOPES";
field public static final String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
- field @RequiresPermission(android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY) public static final String EXTRA_PASSWORD_COMPLEXITY = "android.app.extra.PASSWORD_COMPLEXITY";
+ field @RequiresPermission(android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY) public static final String EXTRA_PASSWORD_COMPLEXITY = "android.app.extra.PASSWORD_COMPLEXITY";
field public static final String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
field public static final String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
@@ -6951,8 +6951,8 @@ package android.app.admin {
field public static final int WIPE_SILENTLY = 8; // 0x8
}
- public abstract static class DevicePolicyManager.InstallUpdateCallback {
- ctor public DevicePolicyManager.InstallUpdateCallback();
+ public abstract static class DevicePolicyManager.InstallSystemUpdateCallback {
+ ctor public DevicePolicyManager.InstallSystemUpdateCallback();
method public void onInstallUpdateError(int, String);
field public static final int UPDATE_ERROR_BATTERY_LOW = 5; // 0x5
field public static final int UPDATE_ERROR_FILE_NOT_FOUND = 4; // 0x4
@@ -9517,7 +9517,6 @@ package android.content {
method public static void cancelSync(android.content.SyncRequest);
method @Nullable public final android.net.Uri canonicalize(@NonNull android.net.Uri);
method public final int delete(@RequiresPermission.Write @NonNull android.net.Uri, @Nullable String, @Nullable String[]);
- method public android.os.Bundle getCache(android.net.Uri);
method @Deprecated public static android.content.SyncInfo getCurrentSync();
method public static java.util.List<android.content.SyncInfo> getCurrentSyncs();
method public static int getIsSyncable(android.accounts.Account, String);
@@ -9548,7 +9547,6 @@ package android.content {
method @Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
method @Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle) throws java.io.FileNotFoundException;
method @Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
- method public void putCache(android.net.Uri, android.os.Bundle);
method @Nullable public final android.database.Cursor query(@RequiresPermission.Read @NonNull android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String);
method @Nullable public final android.database.Cursor query(@RequiresPermission.Read @NonNull android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String, @Nullable android.os.CancellationSignal);
method @Nullable public final android.database.Cursor query(@RequiresPermission.Read @NonNull android.net.Uri, @Nullable String[], @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal);
@@ -11482,7 +11480,6 @@ package android.content.pm {
method public void setOriginatingUri(@Nullable android.net.Uri);
method public void setReferrerUri(@Nullable android.net.Uri);
method public void setSize(long);
- method public void setStaged();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionParams> CREATOR;
field public static final int MODE_FULL_INSTALL = 1; // 0x1
@@ -14099,6 +14096,34 @@ package android.graphics {
ctor @Deprecated public EmbossMaskFilter(float[], float, float, float);
}
+ public class HardwareRenderer {
+ ctor public HardwareRenderer();
+ method public void clearContent();
+ method public android.graphics.HardwareRenderer.FrameRenderRequest createRenderRequest();
+ method public void destroy();
+ method public boolean isOpaque();
+ method public void notifyFramePending();
+ method public void setContentRoot(@Nullable android.graphics.RenderNode);
+ method public void setLightSourceAlpha(@FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=0.0f, to=1.0f) float);
+ method public void setLightSourceGeometry(float, float, float, float);
+ method public void setName(String);
+ method public void setOpaque(boolean);
+ method public void setStopped(boolean);
+ method public void setSurface(@Nullable android.view.Surface);
+ field public static final int SYNC_CONTEXT_IS_STOPPED = 4; // 0x4
+ field public static final int SYNC_FRAME_DROPPED = 8; // 0x8
+ field public static final int SYNC_LOST_SURFACE_REWARD_IF_FOUND = 2; // 0x2
+ field public static final int SYNC_OK = 0; // 0x0
+ field public static final int SYNC_REDRAW_REQUESTED = 1; // 0x1
+ }
+
+ public final class HardwareRenderer.FrameRenderRequest {
+ method public android.graphics.HardwareRenderer.FrameRenderRequest setFrameCommitCallback(@NonNull java.util.concurrent.Executor, @NonNull Runnable);
+ method public android.graphics.HardwareRenderer.FrameRenderRequest setVsyncTime(long);
+ method public android.graphics.HardwareRenderer.FrameRenderRequest setWaitForPresent(boolean);
+ method public int syncAndDraw();
+ }
+
public final class ImageDecoder implements java.lang.AutoCloseable {
method public void close();
method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(@NonNull android.content.res.Resources, int);
@@ -15409,28 +15434,38 @@ package android.graphics.drawable {
method public float getGradientCenterY();
method public float getGradientRadius();
method public int getGradientType();
+ method public int getInnerRadius();
+ method public float getInnerRadiusRatio();
method public int getOpacity();
method public android.graphics.drawable.GradientDrawable.Orientation getOrientation();
method public int getShape();
+ method public int getThickness();
+ method public float getThicknessRatio();
method public boolean getUseLevel();
method public void setAlpha(int);
method public void setColor(@ColorInt int);
method public void setColor(@Nullable android.content.res.ColorStateList);
method public void setColorFilter(@Nullable android.graphics.ColorFilter);
method public void setColors(@ColorInt int[]);
+ method public void setColors(@ColorInt int[], @Nullable float[]);
method public void setCornerRadii(@Nullable float[]);
method public void setCornerRadius(float);
method public void setDither(boolean);
method public void setGradientCenter(float, float);
method public void setGradientRadius(float);
method public void setGradientType(int);
+ method public void setInnerRadius(int);
+ method public void setInnerRadiusRatio(float);
method public void setOrientation(android.graphics.drawable.GradientDrawable.Orientation);
+ method public void setPadding(int, int, int, int);
method public void setShape(int);
method public void setSize(int, int);
method public void setStroke(int, @ColorInt int);
method public void setStroke(int, android.content.res.ColorStateList);
method public void setStroke(int, @ColorInt int, float, float);
method public void setStroke(int, android.content.res.ColorStateList, float, float);
+ method public void setThickness(int);
+ method public void setThicknessRatio(float);
method public void setUseLevel(boolean);
field public static final int LINE = 2; // 0x2
field public static final int LINEAR_GRADIENT = 0; // 0x0
@@ -16492,6 +16527,7 @@ package android.hardware.biometrics {
field public static final int BIOMETRIC_ERROR_LOCKOUT = 7; // 0x7
field public static final int BIOMETRIC_ERROR_LOCKOUT_PERMANENT = 9; // 0x9
field public static final int BIOMETRIC_ERROR_NO_BIOMETRICS = 11; // 0xb
+ field public static final int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14; // 0xe
field public static final int BIOMETRIC_ERROR_NO_SPACE = 4; // 0x4
field public static final int BIOMETRIC_ERROR_TIMEOUT = 3; // 0x3
field public static final int BIOMETRIC_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
@@ -16514,8 +16550,8 @@ package android.hardware.biometrics {
public static class BiometricPrompt.Builder {
ctor public BiometricPrompt.Builder(android.content.Context);
method public android.hardware.biometrics.BiometricPrompt build();
+ method public android.hardware.biometrics.BiometricPrompt.Builder setAllowDeviceCredential(boolean);
method public android.hardware.biometrics.BiometricPrompt.Builder setDescription(@NonNull CharSequence);
- method public android.hardware.biometrics.BiometricPrompt.Builder setEnableFallback(boolean);
method public android.hardware.biometrics.BiometricPrompt.Builder setNegativeButton(@NonNull CharSequence, @NonNull java.util.concurrent.Executor, @NonNull android.content.DialogInterface.OnClickListener);
method public android.hardware.biometrics.BiometricPrompt.Builder setRequireConfirmation(boolean);
method public android.hardware.biometrics.BiometricPrompt.Builder setSubtitle(@NonNull CharSequence);
@@ -22666,6 +22702,7 @@ package android.location {
field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
field public static final int MULTIPATH_INDICATOR_NOT_DETECTED = 2; // 0x2
field public static final int MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+ field public static final int STATE_2ND_CODE_LOCK = 65536; // 0x10000
field public static final int STATE_BDS_D2_BIT_SYNC = 256; // 0x100
field public static final int STATE_BDS_D2_SUBFRAME_SYNC = 512; // 0x200
field public static final int STATE_BIT_SYNC = 2; // 0x2
@@ -24538,7 +24575,9 @@ package android.media {
}
public static final class MediaCodecInfo.VideoCapabilities.PerformancePoint {
+ ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(int, int, int);
method public boolean covers(@NonNull android.media.MediaFormat);
+ method public boolean covers(@NonNull android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint);
field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_100;
field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_120;
field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_200;
@@ -24573,8 +24612,8 @@ package android.media {
field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_50;
field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_60;
field public final int frameRate;
- field public final int height;
- field public final int width;
+ field public final long macroBlockRate;
+ field public final int macroBlocks;
}
public final class MediaCodecList {
@@ -27434,6 +27473,7 @@ package android.media.session {
method public void seekTo(long);
method public void sendCustomAction(@NonNull android.media.session.PlaybackState.CustomAction, @Nullable android.os.Bundle);
method public void sendCustomAction(@NonNull String, @Nullable android.os.Bundle);
+ method public void setPlaybackSpeed(float);
method public void setRating(android.media.Rating);
method public void skipToNext();
method public void skipToPrevious();
@@ -27484,6 +27524,7 @@ package android.media.session {
method public void onPrepareFromUri(android.net.Uri, android.os.Bundle);
method public void onRewind();
method public void onSeekTo(long);
+ method public void onSetPlaybackSpeed(float);
method public void onSetRating(@NonNull android.media.Rating);
method public void onSkipToNext();
method public void onSkipToPrevious();
@@ -30108,10 +30149,14 @@ package android.net.wifi.aware {
method public void onIdentityChanged(byte[]);
}
- public final class PeerHandle implements android.os.Parcelable {
+ public final class ParcelablePeerHandle extends android.net.wifi.aware.PeerHandle implements android.os.Parcelable {
+ ctor public ParcelablePeerHandle(android.net.wifi.aware.PeerHandle);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.wifi.aware.PeerHandle> CREATOR;
+ field public static final android.os.Parcelable.Creator<android.net.wifi.aware.ParcelablePeerHandle> CREATOR;
+ }
+
+ public class PeerHandle {
}
public final class PublishConfig implements android.os.Parcelable {
@@ -35035,7 +35080,7 @@ package android.os {
method public android.os.PowerManager.WakeLock newWakeLock(int, String);
method public void reboot(String);
method public void registerThermalStatusCallback(@NonNull android.os.PowerManager.ThermalStatusCallback, @NonNull java.util.concurrent.Executor);
- method public void unregisterThermalStatusCallback(android.os.PowerManager.ThermalStatusCallback);
+ method public void unregisterThermalStatusCallback(@NonNull android.os.PowerManager.ThermalStatusCallback);
field public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000
field public static final String ACTION_DEVICE_IDLE_MODE_CHANGED = "android.os.action.DEVICE_IDLE_MODE_CHANGED";
field public static final String ACTION_POWER_SAVE_MODE_CHANGED = "android.os.action.POWER_SAVE_MODE_CHANGED";
@@ -44366,6 +44411,7 @@ package android.telephony {
method public int getChannelNumber();
method public String getMccString();
method public String getMncString();
+ method public long getNci();
method public int getPci();
method public int getTac();
method public void writeToParcel(android.os.Parcel, int);
@@ -44379,6 +44425,7 @@ package android.telephony {
method public String getMccString();
method public String getMncString();
method @Nullable public String getMobileNetworkOperator();
+ method public int getUarfcn();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityTdscdma> CREATOR;
}
@@ -45053,12 +45100,12 @@ package android.telephony {
method public boolean canChangeDtmfToneLength();
method @Nullable public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle);
method public android.telephony.TelephonyManager createForSubscriptionId(int);
- method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public java.util.List<android.telephony.CellInfo> getAllCellInfo();
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public java.util.List<android.telephony.CellInfo> getAllCellInfo();
method public int getCallState();
method public int getCardIdForDefaultEuicc();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @WorkerThread public android.os.PersistableBundle getCarrierConfig();
method public int getCarrierIdFromSimMccMnc();
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.telephony.CellLocation getCellLocation();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.telephony.CellLocation getCellLocation();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @Nullable public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getCurrentEmergencyNumberList();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @Nullable public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getCurrentEmergencyNumberList(int);
method public int getDataActivity();
@@ -45088,7 +45135,7 @@ package android.telephony {
method public int getPhoneCount();
method public int getPhoneType();
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE}) public int getPreferredOpportunisticDataSubscription();
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telephony.ServiceState getServiceState();
+ method @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public android.telephony.ServiceState getServiceState();
method @Nullable public android.telephony.SignalStrength getSignalStrength();
method public int getSimCarrierId();
method @Nullable public CharSequence getSimCarrierIdName();
@@ -45130,8 +45177,8 @@ package android.telephony {
method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle);
method public boolean isWorldPhone();
method public void listen(android.telephony.PhoneStateListener, int);
- method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void requestCellInfoUpdate(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void requestCellInfoUpdate(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
+ method @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback);
method public void sendDialerSpecialCode(String);
method public String sendEnvelopeWithStatus(String);
method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
@@ -45200,7 +45247,6 @@ package android.telephony {
field public static final String EXTRA_STATE_RINGING;
field public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.extra.SUBSCRIPTION_ID";
field public static final String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER";
- field public static final int INVALID_CARD_ID = -1; // 0xffffffff
field public static final String METADATA_HIDE_VOICEMAIL_SETTINGS_MENU = "android.telephony.HIDE_VOICEMAIL_SETTINGS_MENU";
field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7
field public static final int NETWORK_TYPE_CDMA = 4; // 0x4
@@ -45226,6 +45272,9 @@ package android.telephony {
field public static final int PHONE_TYPE_GSM = 1; // 0x1
field public static final int PHONE_TYPE_NONE = 0; // 0x0
field public static final int PHONE_TYPE_SIP = 3; // 0x3
+ field public static final int SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER = 2; // 0x2
+ field public static final int SET_OPPORTUNISTIC_SUB_SUCCESS = 0; // 0x0
+ field public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1; // 0x1
field public static final int SIM_STATE_ABSENT = 1; // 0x1
field public static final int SIM_STATE_CARD_IO_ERROR = 8; // 0x8
field public static final int SIM_STATE_CARD_RESTRICTED = 9; // 0x9
@@ -45236,7 +45285,9 @@ package android.telephony {
field public static final int SIM_STATE_PUK_REQUIRED = 3; // 0x3
field public static final int SIM_STATE_READY = 5; // 0x5
field public static final int SIM_STATE_UNKNOWN = 0; // 0x0
+ field public static final int UNINITIALIZED_CARD_ID = -2; // 0xfffffffe
field public static final int UNKNOWN_CARRIER_ID = -1; // 0xffffffff
+ field public static final int UNSUPPORTED_CARD_ID = -1; // 0xffffffff
field public static final int USSD_ERROR_SERVICE_UNAVAIL = -2; // 0xfffffffe
field public static final int USSD_RETURN_FAILURE = -1; // 0xffffffff
field public static final String VVM_TYPE_CVVM = "vvm_type_cvvm";
@@ -45590,6 +45641,483 @@ package android.telephony.gsm {
}
+package android.telephony.ims {
+
+ public class Rcs1To1Thread extends android.telephony.ims.RcsThread {
+ method @WorkerThread public long getFallbackThreadId() throws android.telephony.ims.RcsMessageStoreException;
+ method @NonNull @WorkerThread public android.telephony.ims.RcsParticipant getRecipient() throws android.telephony.ims.RcsMessageStoreException;
+ method public boolean isGroup();
+ method @WorkerThread public void setFallbackThreadId(long) throws android.telephony.ims.RcsMessageStoreException;
+ }
+
+ public abstract class RcsEvent {
+ ctor protected RcsEvent(long);
+ method public long getTimestamp();
+ }
+
+ public final class RcsEventQueryParams implements android.os.Parcelable {
+ method public int describeContents();
+ method @android.telephony.ims.RcsEventQueryParams.EventType public int getEventType();
+ method public int getLimit();
+ method public boolean getSortDirection();
+ method public int getSortingProperty();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int ALL_EVENTS = -1; // 0xffffffff
+ field public static final int ALL_GROUP_THREAD_EVENTS = 0; // 0x0
+ field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsEventQueryParams> CREATOR;
+ field public static final int GROUP_THREAD_ICON_CHANGED_EVENT = 8; // 0x8
+ field public static final int GROUP_THREAD_NAME_CHANGED_EVENT = 16; // 0x10
+ field public static final int GROUP_THREAD_PARTICIPANT_JOINED_EVENT = 2; // 0x2
+ field public static final int GROUP_THREAD_PARTICIPANT_LEFT_EVENT = 4; // 0x4
+ field public static final int PARTICIPANT_ALIAS_CHANGED_EVENT = 1; // 0x1
+ field public static final int SORT_BY_CREATION_ORDER = 0; // 0x0
+ field public static final int SORT_BY_TIMESTAMP = 1; // 0x1
+ }
+
+ public static class RcsEventQueryParams.Builder {
+ ctor public RcsEventQueryParams.Builder();
+ method public android.telephony.ims.RcsEventQueryParams build();
+ method @CheckResult public android.telephony.ims.RcsEventQueryParams.Builder setEventType(@android.telephony.ims.RcsEventQueryParams.EventType int);
+ method @CheckResult public android.telephony.ims.RcsEventQueryParams.Builder setGroupThread(@NonNull android.telephony.ims.RcsGroupThread);
+ method @CheckResult public android.telephony.ims.RcsEventQueryParams.Builder setResultLimit(@IntRange(from=0) int) throws java.security.InvalidParameterException;
+ method @CheckResult public android.telephony.ims.RcsEventQueryParams.Builder setSortDirection(boolean);
+ method @CheckResult public android.telephony.ims.RcsEventQueryParams.Builder setSortProperty(@android.telephony.ims.RcsEventQueryParams.SortingProperty int);
+ }
+
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.telephony.ims.RcsEventQueryParams.ALL_EVENTS, android.telephony.ims.RcsEventQueryParams.ALL_GROUP_THREAD_EVENTS, android.telephony.ims.RcsEventQueryParams.PARTICIPANT_ALIAS_CHANGED_EVENT, android.telephony.ims.RcsEventQueryParams.GROUP_THREAD_PARTICIPANT_JOINED_EVENT, android.telephony.ims.RcsEventQueryParams.GROUP_THREAD_PARTICIPANT_LEFT_EVENT, android.telephony.ims.RcsEventQueryParams.GROUP_THREAD_NAME_CHANGED_EVENT, android.telephony.ims.RcsEventQueryParams.GROUP_THREAD_ICON_CHANGED_EVENT}) public static @interface RcsEventQueryParams.EventType {
+ }
+
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.telephony.ims.RcsEventQueryParams.SORT_BY_CREATION_ORDER, android.telephony.ims.RcsEventQueryParams.SORT_BY_TIMESTAMP}) public static @interface RcsEventQueryParams.SortingProperty {
+ }
+
+ public final class RcsEventQueryResult implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.telephony.ims.RcsQueryContinuationToken getContinuationToken();
+ method public java.util.List<android.telephony.ims.RcsEvent> getEvents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsEventQueryResult> CREATOR;
+ }
+
+ public final class RcsFileTransferCreationParams implements android.os.Parcelable {
+ method public int describeContents();
+ method public String getContentMimeType();
+ method public android.net.Uri getContentUri();
+ method public long getFileSize();
+ method @android.telephony.ims.RcsFileTransferPart.RcsFileTransferStatus public int getFileTransferStatus();
+ method public int getHeight();
+ method public long getMediaDuration();
+ method public String getPreviewMimeType();
+ method public android.net.Uri getPreviewUri();
+ method public String getRcsFileTransferSessionId();
+ method public long getTransferOffset();
+ method public int getWidth();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsFileTransferCreationParams> CREATOR;
+ }
+
+ public class RcsFileTransferCreationParams.Builder {
+ ctor public RcsFileTransferCreationParams.Builder();
+ method public android.telephony.ims.RcsFileTransferCreationParams build();
+ method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setContentMimeType(String);
+ method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setContentUri(android.net.Uri);
+ method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setFileSize(long);
+ method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setFileTransferSessionId(String);
+ method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setFileTransferStatus(@android.telephony.ims.RcsFileTransferPart.RcsFileTransferStatus int);
+ method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setHeight(int);
+ method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setMediaDuration(long);
+ method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setPreviewMimeType(String);
+ method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setPreviewUri(android.net.Uri);
+ method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setTransferOffset(long);
+ method @CheckResult public android.telephony.ims.RcsFileTransferCreationParams.Builder setWidth(int);
+ }
+
+ public class RcsFileTransferPart {
+ method @WorkerThread @Nullable public String getContentMimeType() throws android.telephony.ims.RcsMessageStoreException;
+ method @Nullable @WorkerThread public android.net.Uri getContentUri() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public long getFileSize() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public String getFileTransferSessionId() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread @android.telephony.ims.RcsFileTransferPart.RcsFileTransferStatus public int getFileTransferStatus() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public int getHeight() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public long getLength() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public String getPreviewMimeType() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public android.net.Uri getPreviewUri() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public long getTransferOffset() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public int getWidth() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setContentMimeType(String) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setContentUri(android.net.Uri) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setFileSize(long) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setFileTransferSessionId(String) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setFileTransferStatus(@android.telephony.ims.RcsFileTransferPart.RcsFileTransferStatus int) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setHeight(int) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setLength(long) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setPreviewMimeType(String) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setPreviewUri(android.net.Uri) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setTransferOffset(long) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setWidth(int) throws android.telephony.ims.RcsMessageStoreException;
+ field public static final int DOWNLOADING = 6; // 0x6
+ field public static final int DOWNLOADING_CANCELLED = 9; // 0x9
+ field public static final int DOWNLOADING_FAILED = 8; // 0x8
+ field public static final int DOWNLOADING_PAUSED = 7; // 0x7
+ field public static final int DRAFT = 1; // 0x1
+ field public static final int NOT_SET = 0; // 0x0
+ field public static final int SENDING = 2; // 0x2
+ field public static final int SENDING_CANCELLED = 5; // 0x5
+ field public static final int SENDING_FAILED = 4; // 0x4
+ field public static final int SENDING_PAUSED = 3; // 0x3
+ field public static final int SUCCEEDED = 10; // 0xa
+ }
+
+ @IntDef({android.telephony.ims.RcsFileTransferPart.DRAFT, android.telephony.ims.RcsFileTransferPart.SENDING, android.telephony.ims.RcsFileTransferPart.SENDING_PAUSED, android.telephony.ims.RcsFileTransferPart.SENDING_FAILED, android.telephony.ims.RcsFileTransferPart.SENDING_CANCELLED, android.telephony.ims.RcsFileTransferPart.DOWNLOADING, android.telephony.ims.RcsFileTransferPart.DOWNLOADING_PAUSED, android.telephony.ims.RcsFileTransferPart.DOWNLOADING_FAILED, android.telephony.ims.RcsFileTransferPart.DOWNLOADING_CANCELLED, android.telephony.ims.RcsFileTransferPart.SUCCEEDED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RcsFileTransferPart.RcsFileTransferStatus {
+ }
+
+ public class RcsGroupThread extends android.telephony.ims.RcsThread {
+ method @WorkerThread public void addParticipant(@NonNull android.telephony.ims.RcsParticipant) throws android.telephony.ims.RcsMessageStoreException;
+ method @Nullable @WorkerThread public android.net.Uri getConferenceUri() throws android.telephony.ims.RcsMessageStoreException;
+ method @Nullable public android.net.Uri getGroupIcon() throws android.telephony.ims.RcsMessageStoreException;
+ method @Nullable @WorkerThread public String getGroupName() throws android.telephony.ims.RcsMessageStoreException;
+ method @Nullable @WorkerThread public android.telephony.ims.RcsParticipant getOwner() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread @NonNull public java.util.Set<android.telephony.ims.RcsParticipant> getParticipants() throws android.telephony.ims.RcsMessageStoreException;
+ method public boolean isGroup();
+ method @WorkerThread public void removeParticipant(@NonNull android.telephony.ims.RcsParticipant) throws android.telephony.ims.RcsMessageStoreException;
+ method @Nullable @WorkerThread public void setConferenceUri(android.net.Uri) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setGroupIcon(@Nullable android.net.Uri) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setGroupName(String) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setOwner(@Nullable android.telephony.ims.RcsParticipant) throws android.telephony.ims.RcsMessageStoreException;
+ }
+
+ public abstract class RcsGroupThreadEvent extends android.telephony.ims.RcsEvent {
+ method @NonNull public android.telephony.ims.RcsParticipant getOriginatingParticipant();
+ method @NonNull public android.telephony.ims.RcsGroupThread getRcsGroupThread();
+ }
+
+ public final class RcsGroupThreadIconChangedEvent extends android.telephony.ims.RcsGroupThreadEvent implements android.os.Parcelable {
+ ctor public RcsGroupThreadIconChangedEvent(long, @NonNull android.telephony.ims.RcsGroupThread, @NonNull android.telephony.ims.RcsParticipant, @Nullable android.net.Uri);
+ method public int describeContents();
+ method @Nullable public android.net.Uri getNewIcon();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsGroupThreadIconChangedEvent> CREATOR;
+ }
+
+ public final class RcsGroupThreadNameChangedEvent extends android.telephony.ims.RcsGroupThreadEvent implements android.os.Parcelable {
+ ctor public RcsGroupThreadNameChangedEvent(long, @NonNull android.telephony.ims.RcsGroupThread, @NonNull android.telephony.ims.RcsParticipant, @Nullable String);
+ method public int describeContents();
+ method @Nullable public String getNewName();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsGroupThreadNameChangedEvent> CREATOR;
+ }
+
+ public final class RcsGroupThreadParticipantJoinedEvent extends android.telephony.ims.RcsGroupThreadEvent implements android.os.Parcelable {
+ ctor public RcsGroupThreadParticipantJoinedEvent(long, @NonNull android.telephony.ims.RcsGroupThread, @NonNull android.telephony.ims.RcsParticipant, @NonNull android.telephony.ims.RcsParticipant);
+ method public int describeContents();
+ method public android.telephony.ims.RcsParticipant getJoinedParticipant();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsGroupThreadParticipantJoinedEvent> CREATOR;
+ }
+
+ public final class RcsGroupThreadParticipantLeftEvent extends android.telephony.ims.RcsGroupThreadEvent implements android.os.Parcelable {
+ ctor public RcsGroupThreadParticipantLeftEvent(long, @NonNull android.telephony.ims.RcsGroupThread, @NonNull android.telephony.ims.RcsParticipant, @NonNull android.telephony.ims.RcsParticipant);
+ method public int describeContents();
+ method @NonNull public android.telephony.ims.RcsParticipant getLeavingParticipantId();
+ method public void persist() throws android.telephony.ims.RcsMessageStoreException;
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsGroupThreadParticipantLeftEvent> CREATOR;
+ }
+
+ public class RcsIncomingMessage extends android.telephony.ims.RcsMessage {
+ method @WorkerThread public long getArrivalTimestamp() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public long getSeenTimestamp() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public android.telephony.ims.RcsParticipant getSenderParticipant() throws android.telephony.ims.RcsMessageStoreException;
+ method public boolean isIncoming();
+ method @WorkerThread public void setArrivalTimestamp(long) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setSeenTimestamp(long) throws android.telephony.ims.RcsMessageStoreException;
+ }
+
+ public final class RcsIncomingMessageCreationParams extends android.telephony.ims.RcsMessageCreationParams implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getArrivalTimestamp();
+ method public long getSeenTimestamp();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsIncomingMessageCreationParams> CREATOR;
+ }
+
+ public static class RcsIncomingMessageCreationParams.Builder extends android.telephony.ims.RcsMessageCreationParams.Builder {
+ ctor public RcsIncomingMessageCreationParams.Builder(long, long, int);
+ method public android.telephony.ims.RcsIncomingMessageCreationParams build();
+ method @CheckResult public android.telephony.ims.RcsIncomingMessageCreationParams.Builder setArrivalTimestamp(long);
+ method @CheckResult public android.telephony.ims.RcsIncomingMessageCreationParams.Builder setSeenTimestamp(long);
+ method @CheckResult public android.telephony.ims.RcsIncomingMessageCreationParams.Builder setSenderParticipant(android.telephony.ims.RcsParticipant);
+ }
+
+ public class RcsManager {
+ method public android.telephony.ims.RcsMessageStore getRcsMessageStore();
+ }
+
+ public abstract class RcsMessage {
+ method @NonNull @WorkerThread public java.util.Set<android.telephony.ims.RcsFileTransferPart> getFileTransferParts() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public double getLatitude() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public double getLongitude() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public long getOriginationTimestamp() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public String getRcsMessageId() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread @android.telephony.ims.RcsMessage.RcsMessageStatus public int getStatus() throws android.telephony.ims.RcsMessageStoreException;
+ method public int getSubscriptionId() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public String getText() throws android.telephony.ims.RcsMessageStoreException;
+ method @NonNull @WorkerThread public android.telephony.ims.RcsFileTransferPart insertFileTransfer(android.telephony.ims.RcsFileTransferCreationParams) throws android.telephony.ims.RcsMessageStoreException;
+ method public abstract boolean isIncoming();
+ method @WorkerThread public void removeFileTransferPart(@NonNull android.telephony.ims.RcsFileTransferPart) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setLatitude(double) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setLongitude(double) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setOriginationTimestamp(long) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setRcsMessageId(String) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setStatus(@android.telephony.ims.RcsMessage.RcsMessageStatus int) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setSubscriptionId(int) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setText(String) throws android.telephony.ims.RcsMessageStoreException;
+ field public static final int DRAFT = 1; // 0x1
+ field public static final int FAILED = 6; // 0x6
+ field public static final double LOCATION_NOT_SET = 4.9E-324;
+ field public static final int NOT_SET = 0; // 0x0
+ field public static final int QUEUED = 2; // 0x2
+ field public static final int RECEIVED = 7; // 0x7
+ field public static final int RETRYING = 5; // 0x5
+ field public static final int SEEN = 9; // 0x9
+ field public static final int SENDING = 3; // 0x3
+ field public static final int SENT = 4; // 0x4
+ }
+
+ @IntDef({android.telephony.ims.RcsMessage.DRAFT, android.telephony.ims.RcsMessage.QUEUED, android.telephony.ims.RcsMessage.SENDING, android.telephony.ims.RcsMessage.SENT, android.telephony.ims.RcsMessage.RETRYING, android.telephony.ims.RcsMessage.FAILED, android.telephony.ims.RcsMessage.RECEIVED, android.telephony.ims.RcsMessage.SEEN}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RcsMessage.RcsMessageStatus {
+ }
+
+ public class RcsMessageCreationParams {
+ ctor protected RcsMessageCreationParams(android.telephony.ims.RcsMessageCreationParams.Builder);
+ method public double getLatitude();
+ method public double getLongitude();
+ method public int getMessageStatus();
+ method public long getOriginationTimestamp();
+ method @Nullable public String getRcsMessageGlobalId();
+ method public int getSubId();
+ method @Nullable public String getText();
+ }
+
+ public static class RcsMessageCreationParams.Builder {
+ method public android.telephony.ims.RcsMessageCreationParams build();
+ method @CheckResult public android.telephony.ims.RcsMessageCreationParams.Builder setLatitude(double);
+ method @CheckResult public android.telephony.ims.RcsMessageCreationParams.Builder setLongitude(double);
+ method @CheckResult public android.telephony.ims.RcsMessageCreationParams.Builder setRcsMessageId(String);
+ method @CheckResult public android.telephony.ims.RcsMessageCreationParams.Builder setStatus(@android.telephony.ims.RcsMessage.RcsMessageStatus int);
+ method @CheckResult public android.telephony.ims.RcsMessageCreationParams.Builder setText(String);
+ }
+
+ public final class RcsMessageQueryParams implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getFileTransferPresence();
+ method public int getLimit();
+ method public String getMessageLike();
+ method public int getMessageType();
+ method public boolean getSortDirection();
+ method @android.telephony.ims.RcsMessageQueryParams.SortingProperty public int getSortingProperty();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsMessageQueryParams> CREATOR;
+ field public static final int MESSAGES_WITHOUT_FILE_TRANSFERS = 8; // 0x8
+ field public static final int MESSAGES_WITH_FILE_TRANSFERS = 4; // 0x4
+ field public static final int MESSAGE_TYPE_INCOMING = 1; // 0x1
+ field public static final int MESSAGE_TYPE_OUTGOING = 2; // 0x2
+ field public static final int SORT_BY_CREATION_ORDER = 0; // 0x0
+ field public static final int SORT_BY_TIMESTAMP = 1; // 0x1
+ }
+
+ public static class RcsMessageQueryParams.Builder {
+ ctor public RcsMessageQueryParams.Builder();
+ method public android.telephony.ims.RcsMessageQueryParams build();
+ method @CheckResult public android.telephony.ims.RcsMessageQueryParams.Builder setFileTransferPresence(int);
+ method @CheckResult public android.telephony.ims.RcsMessageQueryParams.Builder setMessageLike(String);
+ method @CheckResult public android.telephony.ims.RcsMessageQueryParams.Builder setMessageType(int);
+ method @CheckResult public android.telephony.ims.RcsMessageQueryParams.Builder setResultLimit(@IntRange(from=0) int) throws java.security.InvalidParameterException;
+ method @CheckResult public android.telephony.ims.RcsMessageQueryParams.Builder setSortDirection(boolean);
+ method @CheckResult public android.telephony.ims.RcsMessageQueryParams.Builder setSortProperty(@android.telephony.ims.RcsMessageQueryParams.SortingProperty int);
+ method @CheckResult public android.telephony.ims.RcsMessageQueryParams.Builder setThread(@Nullable android.telephony.ims.RcsThread);
+ }
+
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.telephony.ims.RcsMessageQueryParams.SORT_BY_CREATION_ORDER, android.telephony.ims.RcsMessageQueryParams.SORT_BY_TIMESTAMP}) public static @interface RcsMessageQueryParams.SortingProperty {
+ }
+
+ public final class RcsMessageQueryResult implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.telephony.ims.RcsQueryContinuationToken getContinuationToken();
+ method @NonNull public java.util.List<android.telephony.ims.RcsMessage> getMessages();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsMessageQueryResult> CREATOR;
+ }
+
+ public final class RcsMessageSnippet implements android.os.Parcelable {
+ method public int describeContents();
+ method @android.telephony.ims.RcsMessage.RcsMessageStatus public int getSnippetStatus();
+ method @Nullable public String getSnippetText();
+ method public long getSnippetTimestamp();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsMessageSnippet> CREATOR;
+ }
+
+ public class RcsMessageStore {
+ ctor public RcsMessageStore();
+ method @WorkerThread @NonNull public android.telephony.ims.RcsGroupThread createGroupThread(@Nullable java.util.List<android.telephony.ims.RcsParticipant>, @Nullable String, @Nullable android.net.Uri) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread @NonNull public android.telephony.ims.Rcs1To1Thread createRcs1To1Thread(@NonNull android.telephony.ims.RcsParticipant) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread @NonNull public android.telephony.ims.RcsParticipant createRcsParticipant(String, @Nullable String) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void deleteThread(@NonNull android.telephony.ims.RcsThread) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread @NonNull public android.telephony.ims.RcsEventQueryResult getRcsEvents(@Nullable android.telephony.ims.RcsEventQueryParams) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread @NonNull public android.telephony.ims.RcsEventQueryResult getRcsEvents(@NonNull android.telephony.ims.RcsQueryContinuationToken) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread @NonNull public android.telephony.ims.RcsMessageQueryResult getRcsMessages(@Nullable android.telephony.ims.RcsMessageQueryParams) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread @NonNull public android.telephony.ims.RcsMessageQueryResult getRcsMessages(@NonNull android.telephony.ims.RcsQueryContinuationToken) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread @NonNull public android.telephony.ims.RcsParticipantQueryResult getRcsParticipants(@Nullable android.telephony.ims.RcsParticipantQueryParams) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread @NonNull public android.telephony.ims.RcsParticipantQueryResult getRcsParticipants(@NonNull android.telephony.ims.RcsQueryContinuationToken) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread @NonNull public android.telephony.ims.RcsThreadQueryResult getRcsThreads(@Nullable android.telephony.ims.RcsThreadQueryParams) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread @NonNull public android.telephony.ims.RcsThreadQueryResult getRcsThreads(@NonNull android.telephony.ims.RcsQueryContinuationToken) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread @NonNull public void persistRcsEvent(android.telephony.ims.RcsEvent) throws android.telephony.ims.RcsMessageStoreException;
+ }
+
+ public class RcsMessageStoreException extends java.lang.Exception {
+ ctor public RcsMessageStoreException(String);
+ }
+
+ public class RcsOutgoingMessage extends android.telephony.ims.RcsMessage {
+ method @NonNull @WorkerThread public java.util.List<android.telephony.ims.RcsOutgoingMessageDelivery> getOutgoingDeliveries() throws android.telephony.ims.RcsMessageStoreException;
+ method public boolean isIncoming();
+ }
+
+ public final class RcsOutgoingMessageCreationParams extends android.telephony.ims.RcsMessageCreationParams implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsOutgoingMessageCreationParams> CREATOR;
+ }
+
+ public static class RcsOutgoingMessageCreationParams.Builder extends android.telephony.ims.RcsMessageCreationParams.Builder {
+ ctor public RcsOutgoingMessageCreationParams.Builder(long, int);
+ method public android.telephony.ims.RcsOutgoingMessageCreationParams build();
+ }
+
+ public class RcsOutgoingMessageDelivery {
+ method @WorkerThread public long getDeliveredTimestamp() throws android.telephony.ims.RcsMessageStoreException;
+ method @NonNull public android.telephony.ims.RcsOutgoingMessage getMessage();
+ method @NonNull public android.telephony.ims.RcsParticipant getRecipient();
+ method @WorkerThread public long getSeenTimestamp() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread @android.telephony.ims.RcsMessage.RcsMessageStatus public int getStatus() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setDeliveredTimestamp(long) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setSeenTimestamp(long) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setStatus(@android.telephony.ims.RcsMessage.RcsMessageStatus int) throws android.telephony.ims.RcsMessageStoreException;
+ }
+
+ public class RcsParticipant {
+ method @Nullable @WorkerThread public String getAlias() throws android.telephony.ims.RcsMessageStoreException;
+ method @Nullable @WorkerThread public String getCanonicalAddress() throws android.telephony.ims.RcsMessageStoreException;
+ method @Nullable @WorkerThread public String getContactId() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setAlias(String) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void setContactId(String) throws android.telephony.ims.RcsMessageStoreException;
+ }
+
+ public final class RcsParticipantAliasChangedEvent extends android.telephony.ims.RcsEvent implements android.os.Parcelable {
+ ctor public RcsParticipantAliasChangedEvent(long, @NonNull android.telephony.ims.RcsParticipant, @Nullable String);
+ method public int describeContents();
+ method @Nullable public String getNewAlias();
+ method @NonNull public android.telephony.ims.RcsParticipant getParticipantId();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsParticipantAliasChangedEvent> CREATOR;
+ }
+
+ public final class RcsParticipantQueryParams implements android.os.Parcelable {
+ method public int describeContents();
+ method public String getAliasLike();
+ method public String getCanonicalAddressLike();
+ method public int getLimit();
+ method public boolean getSortDirection();
+ method public int getSortingProperty();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsParticipantQueryParams> CREATOR;
+ field public static final int SORT_BY_ALIAS = 1; // 0x1
+ field public static final int SORT_BY_CANONICAL_ADDRESS = 2; // 0x2
+ field public static final int SORT_BY_CREATION_ORDER = 0; // 0x0
+ }
+
+ public static class RcsParticipantQueryParams.Builder {
+ ctor public RcsParticipantQueryParams.Builder();
+ method public android.telephony.ims.RcsParticipantQueryParams build();
+ method @CheckResult public android.telephony.ims.RcsParticipantQueryParams.Builder setAliasLike(String);
+ method @CheckResult public android.telephony.ims.RcsParticipantQueryParams.Builder setCanonicalAddressLike(String);
+ method @CheckResult public android.telephony.ims.RcsParticipantQueryParams.Builder setResultLimit(@IntRange(from=0) int) throws java.security.InvalidParameterException;
+ method @CheckResult public android.telephony.ims.RcsParticipantQueryParams.Builder setSortDirection(boolean);
+ method @CheckResult public android.telephony.ims.RcsParticipantQueryParams.Builder setSortProperty(@android.telephony.ims.RcsParticipantQueryParams.SortingProperty int);
+ method @CheckResult public android.telephony.ims.RcsParticipantQueryParams.Builder setThread(android.telephony.ims.RcsThread);
+ }
+
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.telephony.ims.RcsParticipantQueryParams.SORT_BY_CREATION_ORDER, android.telephony.ims.RcsParticipantQueryParams.SORT_BY_ALIAS, android.telephony.ims.RcsParticipantQueryParams.SORT_BY_CANONICAL_ADDRESS}) public static @interface RcsParticipantQueryParams.SortingProperty {
+ }
+
+ public final class RcsParticipantQueryResult implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.telephony.ims.RcsQueryContinuationToken getContinuationToken();
+ method @NonNull public java.util.List<android.telephony.ims.RcsParticipant> getParticipants();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsParticipantQueryResult> CREATOR;
+ }
+
+ public final class RcsQueryContinuationToken implements android.os.Parcelable {
+ method public int describeContents();
+ method @android.telephony.ims.RcsQueryContinuationToken.ContinuationTokenType public int getQueryType();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsQueryContinuationToken> CREATOR;
+ field public static final int EVENT_QUERY_CONTINUATION_TOKEN_TYPE = 0; // 0x0
+ field public static final int MESSAGE_QUERY_CONTINUATION_TOKEN_TYPE = 1; // 0x1
+ field public static final int PARTICIPANT_QUERY_CONTINUATION_TOKEN_TYPE = 2; // 0x2
+ field public static final int THREAD_QUERY_CONTINUATION_TOKEN_TYPE = 3; // 0x3
+ }
+
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.telephony.ims.RcsQueryContinuationToken.EVENT_QUERY_CONTINUATION_TOKEN_TYPE, android.telephony.ims.RcsQueryContinuationToken.MESSAGE_QUERY_CONTINUATION_TOKEN_TYPE, android.telephony.ims.RcsQueryContinuationToken.PARTICIPANT_QUERY_CONTINUATION_TOKEN_TYPE, android.telephony.ims.RcsQueryContinuationToken.THREAD_QUERY_CONTINUATION_TOKEN_TYPE}) public static @interface RcsQueryContinuationToken.ContinuationTokenType {
+ }
+
+ public abstract class RcsThread {
+ method @WorkerThread @NonNull public android.telephony.ims.RcsIncomingMessage addIncomingMessage(@NonNull android.telephony.ims.RcsIncomingMessageCreationParams) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread @NonNull public android.telephony.ims.RcsOutgoingMessage addOutgoingMessage(@NonNull android.telephony.ims.RcsOutgoingMessageCreationParams) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread public void deleteMessage(@NonNull android.telephony.ims.RcsMessage) throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread @NonNull public android.telephony.ims.RcsMessageQueryResult getMessages() throws android.telephony.ims.RcsMessageStoreException;
+ method @WorkerThread @NonNull public android.telephony.ims.RcsMessageSnippet getSnippet() throws android.telephony.ims.RcsMessageStoreException;
+ method public abstract boolean isGroup();
+ }
+
+ public final class RcsThreadQueryParams implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getLimit();
+ method public boolean getSortDirection();
+ method @android.telephony.ims.RcsThreadQueryParams.SortingProperty public int getSortingProperty();
+ method public int getThreadType();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsThreadQueryParams> CREATOR;
+ field public static final int SORT_BY_CREATION_ORDER = 0; // 0x0
+ field public static final int SORT_BY_TIMESTAMP = 1; // 0x1
+ field public static final int THREAD_TYPE_1_TO_1 = 2; // 0x2
+ field public static final int THREAD_TYPE_GROUP = 1; // 0x1
+ }
+
+ public static class RcsThreadQueryParams.Builder {
+ ctor public RcsThreadQueryParams.Builder();
+ method public android.telephony.ims.RcsThreadQueryParams build();
+ method @CheckResult public android.telephony.ims.RcsThreadQueryParams.Builder setParticipant(@NonNull android.telephony.ims.RcsParticipant);
+ method @CheckResult public android.telephony.ims.RcsThreadQueryParams.Builder setParticipants(@NonNull java.util.List<android.telephony.ims.RcsParticipant>);
+ method @CheckResult public android.telephony.ims.RcsThreadQueryParams.Builder setResultLimit(@IntRange(from=0) int) throws java.security.InvalidParameterException;
+ method @CheckResult public android.telephony.ims.RcsThreadQueryParams.Builder setSortDirection(boolean);
+ method @CheckResult public android.telephony.ims.RcsThreadQueryParams.Builder setSortProperty(@android.telephony.ims.RcsThreadQueryParams.SortingProperty int);
+ method @CheckResult public android.telephony.ims.RcsThreadQueryParams.Builder setThreadType(int);
+ }
+
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.telephony.ims.RcsThreadQueryParams.SORT_BY_CREATION_ORDER, android.telephony.ims.RcsThreadQueryParams.SORT_BY_TIMESTAMP}) public static @interface RcsThreadQueryParams.SortingProperty {
+ }
+
+ public final class RcsThreadQueryResult implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.telephony.ims.RcsQueryContinuationToken getContinuationToken();
+ method @NonNull public java.util.List<android.telephony.ims.RcsThread> getThreads();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsThreadQueryResult> CREATOR;
+ }
+
+}
+
package android.telephony.mbms {
public class DownloadProgressListener {
@@ -48501,6 +49029,7 @@ package android.util {
}
public final class StatsLog {
+ method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public static boolean logBinaryPushStateChanged(@NonNull String, long, int, int, @NonNull long[]);
method public static boolean logEvent(int);
method public static boolean logStart(int);
method public static boolean logStop(int);
@@ -48994,6 +49523,7 @@ package android.view {
method public boolean[] hasKeys(int...);
method public boolean hasMicrophone();
method public boolean isEnabled();
+ method public boolean isExternal();
method public boolean isVirtual();
method public boolean supportsSource(int);
method public void writeToParcel(android.os.Parcel, int);
@@ -50307,7 +50837,7 @@ package android.view {
method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getAlpha();
method public android.view.animation.Animation getAnimation();
method public android.os.IBinder getApplicationWindowToken();
- method @NonNull public java.util.List<java.lang.Integer> getAttributeResolutionStack();
+ method @NonNull public java.util.List<java.lang.Integer> getAttributeResolutionStack(@AttrRes int);
method @NonNull public java.util.Map<java.lang.Integer,java.lang.Integer> getAttributeSourceResourceMap();
method @android.view.ViewDebug.ExportedProperty @Nullable public String[] getAutofillHints();
method public final android.view.autofill.AutofillId getAutofillId();
@@ -50357,6 +50887,8 @@ package android.view {
method public void getHitRect(android.graphics.Rect);
method public int getHorizontalFadingEdgeLength();
method protected int getHorizontalScrollbarHeight();
+ method @Nullable public android.graphics.drawable.Drawable getHorizontalScrollbarThumbDrawable();
+ method @Nullable public android.graphics.drawable.Drawable getHorizontalScrollbarTrackDrawable();
method @android.view.ViewDebug.CapturedViewProperty @IdRes public int getId();
method @android.view.ViewDebug.ExportedProperty(category="accessibility", mapping={@android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO, to="auto"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES, to="yes"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO, to="no"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, to="noHideDescendants")}) public int getImportantForAccessibility();
method @android.view.ViewDebug.ExportedProperty(mapping={@android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_AUTO, to="auto"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_YES, to="yes"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_NO, to="no"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, to="yesExcludeDescendants"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, to="noExcludeDescendants")}) public int getImportantForAutofill();
@@ -50447,6 +50979,8 @@ package android.view {
method public long getUniqueDrawingId();
method public int getVerticalFadingEdgeLength();
method public int getVerticalScrollbarPosition();
+ method @Nullable public android.graphics.drawable.Drawable getVerticalScrollbarThumbDrawable();
+ method @Nullable public android.graphics.drawable.Drawable getVerticalScrollbarTrackDrawable();
method public int getVerticalScrollbarWidth();
method public android.view.ViewTreeObserver getViewTreeObserver();
method @android.view.ViewDebug.ExportedProperty(mapping={@android.view.ViewDebug.IntToString(from=android.view.View.VISIBLE, to="VISIBLE"), @android.view.ViewDebug.IntToString(from=android.view.View.INVISIBLE, to="INVISIBLE"), @android.view.ViewDebug.IntToString(from=android.view.View.GONE, to="GONE")}) public int getVisibility();
@@ -50690,6 +51224,8 @@ package android.view {
method public void setHasTransientState(boolean);
method public void setHorizontalFadingEdgeEnabled(boolean);
method public void setHorizontalScrollBarEnabled(boolean);
+ method public void setHorizontalScrollbarThumbDrawable(@Nullable android.graphics.drawable.Drawable);
+ method public void setHorizontalScrollbarTrackDrawable(@Nullable android.graphics.drawable.Drawable);
method public void setHovered(boolean);
method public void setId(@IdRes int);
method public void setImportantForAccessibility(int);
@@ -50779,6 +51315,8 @@ package android.view {
method public void setVerticalFadingEdgeEnabled(boolean);
method public void setVerticalScrollBarEnabled(boolean);
method public void setVerticalScrollbarPosition(int);
+ method public void setVerticalScrollbarThumbDrawable(@Nullable android.graphics.drawable.Drawable);
+ method public void setVerticalScrollbarTrackDrawable(@Nullable android.graphics.drawable.Drawable);
method public void setVisibility(int);
method @Deprecated public void setWillNotCacheDrawing(boolean);
method public void setWillNotDraw(boolean);
@@ -51112,6 +51650,7 @@ package android.view {
method public int getScaledHoverSlop();
method public int getScaledMaximumDrawingCacheSize();
method public int getScaledMaximumFlingVelocity();
+ method public int getScaledMinScalingSpan();
method public int getScaledMinimumFlingVelocity();
method public int getScaledOverflingDistance();
method public int getScaledOverscrollDistance();
@@ -51236,6 +51775,7 @@ package android.view {
method public android.view.View getChildAt(int);
method public int getChildCount();
method protected int getChildDrawingOrder(int, int);
+ method public final int getChildDrawingOrder(int);
method public static int getChildMeasureSpec(int, int, int);
method protected boolean getChildStaticTransformation(android.view.View, android.view.animation.Transformation);
method public boolean getChildVisibleRect(android.view.View, android.graphics.Rect, android.graphics.Point);
@@ -52608,7 +53148,6 @@ package android.view.animation {
public abstract class Animation implements java.lang.Cloneable {
ctor public Animation();
ctor public Animation(android.content.Context, android.util.AttributeSet);
- method public void addAnimationListener(android.view.animation.Animation.AnimationListener);
method protected void applyTransformation(float, android.view.animation.Transformation);
method public void cancel();
method protected android.view.animation.Animation clone() throws java.lang.CloneNotSupportedException;
@@ -52633,7 +53172,6 @@ package android.view.animation {
method public void initialize(int, int, int, int);
method public boolean isFillEnabled();
method public boolean isInitialized();
- method public void removeAnimationListener(android.view.animation.Animation.AnimationListener);
method public void reset();
method protected float resolveSize(int, float, int, int);
method public void restrictDuration(long);
@@ -52966,6 +53504,7 @@ package android.view.contentcapture {
method public void close();
method @NonNull public final android.view.contentcapture.ContentCaptureSession createContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureContext);
method public final void destroy();
+ method @Nullable public final android.view.contentcapture.ContentCaptureContext getContentCaptureContext();
method public final android.view.contentcapture.ContentCaptureSessionId getContentCaptureSessionId();
method @NonNull public android.view.autofill.AutofillId newAutofillId(@NonNull android.view.autofill.AutofillId, long);
method @NonNull public final android.view.ViewStructure newVirtualViewStructure(@NonNull android.view.autofill.AutofillId, long);
@@ -52973,6 +53512,7 @@ package android.view.contentcapture {
method public final void notifyViewDisappeared(@NonNull android.view.autofill.AutofillId);
method public final void notifyViewTextChanged(@NonNull android.view.autofill.AutofillId, @Nullable CharSequence);
method public final void notifyViewsDisappeared(@NonNull android.view.autofill.AutofillId, @NonNull long[]);
+ method public final void setContentCaptureContext(@Nullable android.view.contentcapture.ContentCaptureContext);
}
public final class ContentCaptureSessionId implements android.os.Parcelable {
@@ -55246,6 +55786,7 @@ package android.widget {
method public void performCompletion();
method protected void performFiltering(CharSequence, int);
method public void performValidation();
+ method public final void refreshAutoCompleteResults();
method protected void replaceText(CharSequence);
method public <T extends android.widget.ListAdapter & android.widget.Filterable> void setAdapter(T);
method public void setCompletionHint(CharSequence);
@@ -55865,11 +56406,16 @@ package android.widget {
method public boolean executeKeyEvent(android.view.KeyEvent);
method public void fling(int);
method public boolean fullScroll(int);
+ method @ColorInt public int getLeftEdgeEffectColor();
method public int getMaxScrollAmount();
+ method @ColorInt public int getRightEdgeEffectColor();
method public boolean isFillViewport();
method public boolean isSmoothScrollingEnabled();
method public boolean pageScroll(int);
+ method public void setEdgeEffectColor(@ColorInt int);
method public void setFillViewport(boolean);
+ method public void setLeftEdgeEffectColor(@ColorInt int);
+ method public void setRightEdgeEffectColor(@ColorInt int);
method public void setSmoothScrollingEnabled(boolean);
method public final void smoothScrollBy(int, int);
method public final void smoothScrollTo(int, int);
@@ -56010,6 +56556,7 @@ package android.widget {
method @Nullable public android.view.View getAnchorView();
method @StyleRes public int getAnimationStyle();
method @Nullable public android.graphics.drawable.Drawable getBackground();
+ method @Nullable public android.graphics.Rect getEpicenterBounds();
method public int getHeight();
method public int getHorizontalOffset();
method public int getInputMethodMode();
@@ -56036,6 +56583,7 @@ package android.widget {
method public void setBackgroundDrawable(@Nullable android.graphics.drawable.Drawable);
method public void setContentWidth(int);
method public void setDropDownGravity(int);
+ method public void setEpicenterBounds(@Nullable android.graphics.Rect);
method public void setHeight(int);
method public void setHorizontalOffset(int);
method public void setInputMethodMode(int);
@@ -56199,6 +56747,8 @@ package android.widget {
method public int getMaxValue();
method public int getMinValue();
method public int getSelectionDividerHeight();
+ method @ColorInt public int getTextColor();
+ method @FloatRange(from=0.0, fromInclusive=false) public float getTextSize();
method public int getValue();
method public boolean getWrapSelectorWheel();
method public void setDisplayedValues(String[]);
@@ -56209,6 +56759,8 @@ package android.widget {
method public void setOnScrollListener(android.widget.NumberPicker.OnScrollListener);
method public void setOnValueChangedListener(android.widget.NumberPicker.OnValueChangeListener);
method public void setSelectionDividerHeight(@IntRange(from=0) @Px int);
+ method public void setTextColor(@ColorInt int);
+ method public void setTextSize(@FloatRange(from=0.0, fromInclusive=false) float);
method public void setValue(int);
method public void setWrapSelectorWheel(boolean);
}
@@ -56368,6 +56920,7 @@ package android.widget {
ctor public ProgressBar(android.content.Context, android.util.AttributeSet);
ctor public ProgressBar(android.content.Context, android.util.AttributeSet, int);
ctor public ProgressBar(android.content.Context, android.util.AttributeSet, int, int);
+ method @Nullable public android.graphics.drawable.Drawable getCurrentDrawable();
method public android.graphics.drawable.Drawable getIndeterminateDrawable();
method @Nullable public android.content.res.ColorStateList getIndeterminateTintList();
method @Nullable public android.graphics.PorterDuff.Mode getIndeterminateTintMode();
@@ -56665,13 +57218,18 @@ package android.widget {
method public boolean executeKeyEvent(android.view.KeyEvent);
method public void fling(int);
method public boolean fullScroll(int);
+ method @ColorInt public int getBottomEdgeEffectColor();
method public int getMaxScrollAmount();
+ method @ColorInt public int getTopEdgeEffectColor();
method public boolean isFillViewport();
method public boolean isSmoothScrollingEnabled();
method public boolean pageScroll(int);
method public void scrollToDescendant(android.view.View);
+ method public void setBottomEdgeEffectColor(@ColorInt int);
+ method public void setEdgeEffectColor(@ColorInt int);
method public void setFillViewport(boolean);
method public void setSmoothScrollingEnabled(boolean);
+ method public void setTopEdgeEffectColor(@ColorInt int);
method public final void smoothScrollBy(int, int);
method public final void smoothScrollTo(int, int);
}
@@ -61192,9 +61750,9 @@ package java.lang.invoke {
method public String getName();
method public int getReferenceKind();
method public default boolean isVarArgs();
- method public static boolean refKindIsField(int);
- method public static boolean refKindIsValid(int);
- method public static String refKindName(int);
+ method @Deprecated public static boolean refKindIsField(int);
+ method @Deprecated public static boolean refKindIsValid(int);
+ method @Deprecated public static String refKindName(int);
method public static String referenceKindToString(int);
method public <T extends java.lang.reflect.Member> T reflectAs(Class<T>, java.lang.invoke.MethodHandles.Lookup);
method public static String toString(int, Class<?>, String, java.lang.invoke.MethodType);
diff --git a/api/removed.txt b/api/removed.txt
index f5bd434c3cc0..c4ed871d0661 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -558,7 +558,7 @@ package android.telephony {
public class TelephonyManager {
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();
- method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, android.telephony.TelephonyScanManager.NetworkScanCallback);
+ method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, android.telephony.TelephonyScanManager.NetworkScanCallback);
}
}
diff --git a/api/system-current.txt b/api/system-current.txt
index bb7b0b4ea0bf..032851608aac 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -205,6 +205,7 @@ package android {
}
public static final class R.attr {
+ field public static final int allowClearUserDataOnFailedRestore = 16844198; // 0x10105a6
field public static final int inheritShowWhenLocked = 16844194; // 0x10105a2
field public static final int isVrOnly = 16844152; // 0x1010578
field public static final int requiredSystemPropertyName = 16844133; // 0x1010565
@@ -239,6 +240,8 @@ package android {
field public static final int config_defaultAssistant = 17039393; // 0x1040021
field public static final int config_defaultBrowser = 17039394; // 0x1040022
field public static final int config_defaultDialer = 17039395; // 0x1040023
+ field public static final int config_defaultGallery = 17039398; // 0x1040026
+ field public static final int config_defaultMusic = 17039397; // 0x1040025
field public static final int config_defaultSms = 17039396; // 0x1040024
field public static final int config_feedbackIntentExtraKey = 17039391; // 0x104001f
field public static final int config_feedbackIntentNameKey = 17039392; // 0x1040020
@@ -282,9 +285,11 @@ package android.app {
method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void forceStopPackage(String);
method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public static int getCurrentUser();
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getPackageImportance(String);
+ method @NonNull public java.util.Collection<java.util.Locale> getSupportedLocales();
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getUidImportance(int);
method @RequiresPermission(android.Manifest.permission.KILL_UID) public void killUid(int, String);
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
+ method public void setDeviceLocales(@NonNull android.os.LocaleList);
method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public static void setPersistentVrThread(int);
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean switchUser(@NonNull android.os.UserHandle);
}
@@ -309,6 +314,7 @@ package android.app {
method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(String, int, String, int);
method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setUidMode(String, int, int);
field public static final String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
+ field public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility";
field public static final String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
field public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
field public static final String OPSTR_ASSIST_SCREENSHOT = "android:assist_screenshot";
@@ -638,7 +644,7 @@ package android.app.admin {
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean packageHasActiveAdmins(String);
method @Deprecated @RequiresPermission("android.permission.MANAGE_DEVICE_ADMINS") public boolean setActiveProfileOwner(@NonNull android.content.ComponentName, String) throws java.lang.IllegalArgumentException;
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied();
- method public void setProfileOwnerCanAccessDeviceIdsForUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
+ method @RequiresPermission(value=android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, conditional=true) public void setProfileOwnerCanAccessDeviceIdsForUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
field public static final String ACTION_PROVISION_FINALIZATION = "android.app.action.PROVISION_FINALIZATION";
@@ -1148,7 +1154,7 @@ package android.app.usage {
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getAppStandbyBucket(String);
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public java.util.Map<java.lang.String,java.lang.Integer> getAppStandbyBuckets();
method public int getUsageSource();
- method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent);
+ method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerAppUsageObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent);
method public void reportUsageStart(@NonNull android.app.Activity, @NonNull String);
@@ -1280,7 +1286,9 @@ package android.content {
}
public abstract class ContentResolver implements android.content.ContentInterface {
+ method public android.os.Bundle getCache(android.net.Uri);
method public android.graphics.drawable.Drawable getTypeDrawable(String);
+ method public void putCache(android.net.Uri, android.os.Bundle);
}
public abstract class Context {
@@ -1361,6 +1369,7 @@ package android.content {
field public static final String ACTION_INSTALL_INSTANT_APP_PACKAGE = "android.intent.action.INSTALL_INSTANT_APP_PACKAGE";
field public static final String ACTION_INSTANT_APP_RESOLVER_SETTINGS = "android.intent.action.INSTANT_APP_RESOLVER_SETTINGS";
field public static final String ACTION_INTENT_FILTER_NEEDS_VERIFICATION = "android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION";
+ field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_MANAGE_APP_PERMISSION = "android.intent.action.MANAGE_APP_PERMISSION";
field public static final String ACTION_MANAGE_APP_PERMISSIONS = "android.intent.action.MANAGE_APP_PERMISSIONS";
field @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public static final String ACTION_MANAGE_DEFAULT_APP = "android.intent.action.MANAGE_DEFAULT_APP";
field public static final String ACTION_MANAGE_PERMISSIONS = "android.intent.action.MANAGE_PERMISSIONS";
@@ -1371,6 +1380,7 @@ package android.content {
field public static final String ACTION_PRE_BOOT_COMPLETED = "android.intent.action.PRE_BOOT_COMPLETED";
field public static final String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
field public static final String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
+ field public static final String ACTION_REVIEW_ACCESSIBILITY_SERVICES = "android.intent.action.REVIEW_ACCESSIBILITY_SERVICES";
field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_APP_PERMISSION_USAGE = "android.intent.action.REVIEW_APP_PERMISSION_USAGE";
field public static final String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
field public static final String ACTION_REVIEW_PERMISSION_USAGE = "android.intent.action.REVIEW_PERMISSION_USAGE";
@@ -1532,6 +1542,7 @@ package android.content.pm {
method @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) public void setGrantedRuntimePermissions(String[]);
method public void setInstallAsInstantApp(boolean);
method public void setInstallAsVirtualPreload();
+ method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged();
}
public class PackageItemInfo {
@@ -1574,7 +1585,7 @@ package android.content.pm {
method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
method public void sendDeviceCustomizationReadyBroadcast();
method @RequiresPermission(allOf={android.Manifest.permission.SET_PREFERRED_APPLICATIONS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public abstract boolean setDefaultBrowserPackageNameAsUser(String, int);
- method @NonNull @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setDistractingPackageRestrictions(@NonNull String[], @android.content.pm.PackageManager.DistractionRestriction int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setDistractingPackageRestrictions(@NonNull String[], int);
method @RequiresPermission(android.Manifest.permission.SET_HARMFUL_APP_WARNINGS) public void setHarmfulAppWarning(@NonNull String, @Nullable CharSequence);
method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setPackagesSuspended(@Nullable String[], boolean, @Nullable android.os.PersistableBundle, @Nullable android.os.PersistableBundle, @Nullable String);
method @Nullable @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setPackagesSuspended(@Nullable String[], boolean, @Nullable android.os.PersistableBundle, @Nullable android.os.PersistableBundle, @Nullable android.content.pm.SuspendDialogInfo);
@@ -1652,9 +1663,6 @@ package android.content.pm {
method public abstract void onDexModuleRegistered(String, boolean, String);
}
- @IntDef(flag=true, prefix={"RESTRICTION_"}, value={android.content.pm.PackageManager.RESTRICTION_NONE, android.content.pm.PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, android.content.pm.PackageManager.RESTRICTION_HIDE_NOTIFICATIONS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.DistractionRestriction {
- }
-
public static interface PackageManager.OnPermissionsChangedListener {
method public void onPermissionsChanged(int);
}
@@ -5299,6 +5307,10 @@ package android.os {
field public static final android.os.Parcelable.Creator<android.os.IncidentReportArgs> CREATOR;
}
+ public final class LocaleList implements android.os.Parcelable {
+ method public static boolean isPseudoLocale(@Nullable android.icu.util.ULocale);
+ }
+
public final class NativeHandle implements java.io.Closeable {
ctor public NativeHandle();
ctor public NativeHandle(@NonNull java.io.FileDescriptor, boolean);
@@ -5712,6 +5724,7 @@ package android.provider {
method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String);
method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(String, String, String, boolean);
field public static final String NAMESPACE_AUTOFILL = "autofill";
+ field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
field public static final String NAMESPACE_GAME_DRIVER = "game_driver";
field public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
field public static final String NAMESPACE_NETD_NATIVE = "netd_native";
@@ -5741,10 +5754,6 @@ package android.provider {
field public static final String SERVICE_ENABLED = "service_enabled";
}
- public static interface DeviceConfig.ContentCapture {
- field public static final String NAMESPACE = "content_capture";
- }
-
public static interface DeviceConfig.DexBoot {
field public static final String NAMESPACE = "dex_boot";
field public static final String PRIV_APPS_OOB_ENABLED = "priv_apps_oob_enabled";
@@ -5779,6 +5788,18 @@ package android.provider {
field public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled";
}
+ public static interface DeviceConfig.Rollback {
+ field public static final String BOOT_NAMESPACE = "rollback_boot";
+ field public static final String ENABLE_ROLLBACK_TIMEOUT = "enable_rollback_timeout";
+ field public static final String NAMESPACE = "rollback";
+ field public static final String ROLLBACK_LIFETIME_IN_MILLIS = "rollback_lifetime_in_millis";
+ }
+
+ public static interface DeviceConfig.Runtime {
+ field public static final String NAMESPACE = "runtime";
+ field public static final String USE_PRECOMPILED_LAYOUT = "view.precompiled_layout_enabled";
+ }
+
public static interface DeviceConfig.RuntimeNative {
field public static final String NAMESPACE = "runtime_native";
}
@@ -5787,6 +5808,11 @@ package android.provider {
field public static final String NAMESPACE = "runtime_native_boot";
}
+ public static interface DeviceConfig.Scheduler {
+ field public static final String ENABLE_FAST_METRICS_COLLECTION = "enable_fast_metrics_collection";
+ field public static final String NAMESPACE = "scheduler";
+ }
+
public static interface DeviceConfig.Storage {
field public static final String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
field public static final String NAMESPACE = "storage";
@@ -5928,6 +5954,7 @@ package android.provider {
public final class Settings {
field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
field public static final String ACTION_LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS = "android.settings.LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS";
+ field public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE = "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE";
field public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
}
@@ -6283,20 +6310,11 @@ package android.service.autofill.augmented {
}
public abstract class PresentationParams {
- method public int getFlags();
- method @Nullable public android.service.autofill.augmented.PresentationParams.Area getFullArea();
method @Nullable public android.service.autofill.augmented.PresentationParams.Area getSuggestionArea();
- field public static final int FLAG_HINT_GRAVITY_BOTTOM = 2; // 0x2
- field public static final int FLAG_HINT_GRAVITY_LEFT = 4; // 0x4
- field public static final int FLAG_HINT_GRAVITY_RIGHT = 8; // 0x8
- field public static final int FLAG_HINT_GRAVITY_TOP = 1; // 0x1
- field public static final int FLAG_HOST_IME = 16; // 0x10
- field public static final int FLAG_HOST_SYSTEM = 32; // 0x20
}
public abstract static class PresentationParams.Area {
method @NonNull public android.graphics.Rect getBounds();
- method @Nullable public android.service.autofill.augmented.PresentationParams.Area getSubArea(@NonNull android.graphics.Rect);
}
}
@@ -6956,6 +6974,7 @@ package android.telecom {
field public static final String EXTRA_CALL_BACK_INTENT = "android.telecom.extra.CALL_BACK_INTENT";
field public static final String EXTRA_CLEAR_MISSED_CALLS_INTENT = "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT";
field public static final String EXTRA_CONNECTION_SERVICE = "android.telecom.extra.CONNECTION_SERVICE";
+ field public static final String EXTRA_IS_USER_INTENT_EMERGENCY_CALL = "android.telecom.extra.IS_USER_INTENT_EMERGENCY_CALL";
field public static final int TTY_MODE_FULL = 1; // 0x1
field public static final int TTY_MODE_HCO = 2; // 0x2
field public static final int TTY_MODE_OFF = 0; // 0x0
@@ -7019,6 +7038,7 @@ package android.telephony {
method @NonNull public java.util.List<android.service.carrier.CarrierIdentifier> getExcludedCarriers();
method public int getMultiSimPolicy();
method public boolean isAllCarriersAllowed();
+ method public java.util.List<java.lang.Boolean> isCarrierIdentifiersAllowed(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>);
method public void writeToParcel(android.os.Parcel, int);
field public static final int CARRIER_RESTRICTION_DEFAULT_ALLOWED = 1; // 0x1
field public static final int CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED = 0; // 0x0
@@ -7748,6 +7768,7 @@ package android.telephony {
method public void requestEmbeddedSubscriptionInfoListRefresh(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultDataSubId(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultSmsSubId(int);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPreferredDataSubscriptionId(int, boolean, @NonNull java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setSubscriptionEnabled(int, boolean);
field public static final android.net.Uri ADVANCED_CALLING_ENABLED_CONTENT_URI;
field public static final int PROFILE_CLASS_DEFAULT = -1; // 0xffffffff
@@ -7834,12 +7855,13 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isMultisimCarrierRestricted();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRadioOn();
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isRebootRequiredForModemConfigChange();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging();
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isVideoCallingEnabled();
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle);
method public boolean needsOtaServiceProvisioning();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
- method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
+ method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig();
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
@@ -8227,6 +8249,7 @@ package android.telephony.ims {
method public int getServiceType();
method public static int getVideoStateFromCallType(int);
method public static int getVideoStateFromImsCallProfile(android.telephony.ims.ImsCallProfile);
+ method public boolean hasKnownUserIntentEmergency();
method public boolean isEmergencyCallTesting();
method public boolean isVideoCall();
method public boolean isVideoPaused();
@@ -8239,6 +8262,7 @@ package android.telephony.ims {
method public void setEmergencyCallTesting(boolean);
method public void setEmergencyServiceCategories(int);
method public void setEmergencyUrns(java.util.List<java.lang.String>);
+ method public void setHasKnownUserIntentEmergency(boolean);
method public void updateCallExtras(android.telephony.ims.ImsCallProfile);
method public void updateCallType(android.telephony.ims.ImsCallProfile);
method public void updateMediaProfile(android.telephony.ims.ImsCallProfile);
@@ -9303,6 +9327,7 @@ package android.view.contentcapture {
public final class ContentCaptureEvent implements android.os.Parcelable {
method public int describeContents();
+ method @Nullable public android.view.contentcapture.ContentCaptureContext getContentCaptureContext();
method public long getEventTime();
method @Nullable public android.view.autofill.AutofillId getId();
method @Nullable public java.util.List<android.view.autofill.AutofillId> getIds();
@@ -9311,6 +9336,7 @@ package android.view.contentcapture {
method @Nullable public android.view.contentcapture.ViewNode getViewNode();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.view.contentcapture.ContentCaptureEvent> CREATOR;
+ field public static final int TYPE_CONTEXT_UPDATED = 6; // 0x6
field public static final int TYPE_INITIAL_VIEW_TREE_APPEARED = 5; // 0x5
field public static final int TYPE_INITIAL_VIEW_TREE_APPEARING = 4; // 0x4
field public static final int TYPE_VIEW_APPEARED = 1; // 0x1
diff --git a/api/test-current.txt b/api/test-current.txt
index 9be6e811d3de..47d38a7d2f3a 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -996,6 +996,7 @@ package android.net {
method public int[] getCapabilities();
method public int[] getTransportTypes();
method public boolean satisfiedByNetworkCapabilities(android.net.NetworkCapabilities);
+ field public static final int TRANSPORT_TEST = 7; // 0x7
}
public class NetworkStack {
@@ -1785,14 +1786,17 @@ package android.provider {
}
public final class DeviceConfig {
+ method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener);
method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getProperty(String, String);
+ method public static void removeOnPropertyChangedListener(android.provider.DeviceConfig.OnPropertyChangedListener);
method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static void resetToDefaults(int, @Nullable String);
method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static boolean setProperty(String, String, String, boolean);
+ field public static final String NAMESPACE_AUTOFILL = "autofill";
+ field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
}
- public static interface DeviceConfig.ContentCapture {
- field public static final String NAMESPACE = "content_capture";
- field public static final String PROPERTY_CONTENTCAPTURE_ENABLED = "enable_contentcapture";
+ public static interface DeviceConfig.OnPropertyChangedListener {
+ method public void onPropertyChanged(String, String, String);
}
public static interface DeviceConfig.Privacy {
@@ -1812,12 +1816,12 @@ package android.provider {
public final class Settings {
field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
+ field public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE = "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE";
field public static final int RESET_MODE_PACKAGE_DEFAULTS = 1; // 0x1
}
public static final class Settings.Global extends android.provider.Settings.NameValueTable {
field public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
- field public static final String AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS = "autofill_smart_suggestion_emulation_flags";
field public static final String AUTOMATIC_POWER_SAVER_MODE = "automatic_power_saver_mode";
field public static final String CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS = "captive_portal_fallback_probe_specs";
field public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url";
@@ -2071,20 +2075,11 @@ package android.service.autofill.augmented {
}
public abstract class PresentationParams {
- method public int getFlags();
- method @Nullable public android.service.autofill.augmented.PresentationParams.Area getFullArea();
method @Nullable public android.service.autofill.augmented.PresentationParams.Area getSuggestionArea();
- field public static final int FLAG_HINT_GRAVITY_BOTTOM = 2; // 0x2
- field public static final int FLAG_HINT_GRAVITY_LEFT = 4; // 0x4
- field public static final int FLAG_HINT_GRAVITY_RIGHT = 8; // 0x8
- field public static final int FLAG_HINT_GRAVITY_TOP = 1; // 0x1
- field public static final int FLAG_HOST_IME = 16; // 0x10
- field public static final int FLAG_HOST_SYSTEM = 32; // 0x20
}
public abstract static class PresentationParams.Area {
method @NonNull public android.graphics.Rect getBounds();
- method @Nullable public android.service.autofill.augmented.PresentationParams.Area getSubArea(@NonNull android.graphics.Rect);
}
}
@@ -2160,6 +2155,10 @@ package android.telecom {
ctor public CallAudioState(boolean, int, int, @Nullable android.bluetooth.BluetoothDevice, @NonNull java.util.Collection<android.bluetooth.BluetoothDevice>);
}
+ public abstract class Conference extends android.telecom.Conferenceable {
+ method public android.telecom.Connection getPrimaryConnection();
+ }
+
public final class PhoneAccountSuggestion implements android.os.Parcelable {
ctor public PhoneAccountSuggestion(android.telecom.PhoneAccountHandle, int, boolean);
}
@@ -2172,6 +2171,16 @@ package android.telecom {
field public static final String SERVICE_INTERFACE = "android.telecom.PhoneAccountSuggestionService";
}
+ public class TelecomManager {
+ method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getCurrentTtyMode();
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall();
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUserSelectedOutgoingPhoneAccount(android.telecom.PhoneAccountHandle);
+ field public static final int TTY_MODE_FULL = 1; // 0x1
+ field public static final int TTY_MODE_HCO = 2; // 0x2
+ field public static final int TTY_MODE_OFF = 0; // 0x0
+ field public static final int TTY_MODE_VCO = 3; // 0x3
+ }
+
}
package android.telephony {
@@ -2684,6 +2693,8 @@ package android.view.autofill {
public final class AutofillManager {
method public void setAugmentedAutofillWhitelist(@Nullable java.util.List<java.lang.String>, @Nullable java.util.List<android.content.ComponentName>);
+ field public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES = "smart_suggestion_supported_modes";
+ field public static final int FLAG_SMART_SUGGESTION_OFF = 0; // 0x0
field public static final int FLAG_SMART_SUGGESTION_SYSTEM = 1; // 0x1
field public static final int MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS = 120000; // 0x1d4c0
}
@@ -2707,6 +2718,7 @@ package android.view.contentcapture {
public final class ContentCaptureEvent implements android.os.Parcelable {
method public int describeContents();
+ method @Nullable public android.view.contentcapture.ContentCaptureContext getContentCaptureContext();
method public long getEventTime();
method @Nullable public android.view.autofill.AutofillId getId();
method @Nullable public java.util.List<android.view.autofill.AutofillId> getIds();
@@ -2715,6 +2727,7 @@ package android.view.contentcapture {
method @Nullable public android.view.contentcapture.ViewNode getViewNode();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.view.contentcapture.ContentCaptureEvent> CREATOR;
+ field public static final int TYPE_CONTEXT_UPDATED = 6; // 0x6
field public static final int TYPE_INITIAL_VIEW_TREE_APPEARED = 5; // 0x5
field public static final int TYPE_INITIAL_VIEW_TREE_APPEARING = 4; // 0x4
field public static final int TYPE_VIEW_APPEARED = 1; // 0x1
@@ -2725,6 +2738,7 @@ package android.view.contentcapture {
public final class ContentCaptureManager {
method public boolean isContentCaptureFeatureEnabled();
method public void setContentCaptureFeatureEnabled(boolean);
+ field public static final String DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED = "service_explicitly_enabled";
}
public final class ViewNode extends android.app.assist.AssistStructure.ViewNode {
diff --git a/cmds/bootanimation/bootanim.rc b/cmds/bootanimation/bootanim.rc
index 1b3c32b20503..469c9646a4aa 100644
--- a/cmds/bootanimation/bootanim.rc
+++ b/cmds/bootanimation/bootanim.rc
@@ -2,7 +2,6 @@ service bootanim /system/bin/bootanimation
class core animation
user graphics
group graphics audio
- updatable
disabled
oneshot
writepid /dev/stune/top-app/tasks
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index 2fef407a8e3f..d757e4611158 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -56,6 +56,7 @@ cc_library {
shared_libs: [
"libandroidfw",
"libbase",
+ "libcutils",
"libutils",
"libziparchive",
],
@@ -150,6 +151,7 @@ cc_binary {
shared_libs: [
"libandroidfw",
"libbase",
+ "libcutils",
"libidmap2",
"libutils",
"libziparchive",
diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp
index 0c581f3b1a98..6703909d887e 100644
--- a/cmds/idmap2/idmap2/Create.cpp
+++ b/cmds/idmap2/idmap2/Create.cpp
@@ -29,6 +29,7 @@
#include "idmap2/Idmap.h"
#include "idmap2/Policies.h"
#include "idmap2/Result.h"
+#include "idmap2/SysTrace.h"
using android::ApkAssets;
using android::idmap2::BinaryStreamVisitor;
@@ -42,6 +43,7 @@ using android::idmap2::utils::kIdmapFilePermissionMask;
using android::idmap2::utils::UidHasWriteAccessToPath;
bool Create(const std::vector<std::string>& args, std::ostream& out_error) {
+ SYSTRACE << "Create " << args;
std::string target_apk_path;
std::string overlay_apk_path;
std::string idmap_path;
diff --git a/cmds/idmap2/idmap2/Dump.cpp b/cmds/idmap2/idmap2/Dump.cpp
index c8cdcfa6d3dc..3947703fe8da 100644
--- a/cmds/idmap2/idmap2/Dump.cpp
+++ b/cmds/idmap2/idmap2/Dump.cpp
@@ -24,6 +24,7 @@
#include "idmap2/Idmap.h"
#include "idmap2/PrettyPrintVisitor.h"
#include "idmap2/RawPrintVisitor.h"
+#include "idmap2/SysTrace.h"
using android::idmap2::CommandLineOptions;
using android::idmap2::Idmap;
@@ -31,6 +32,7 @@ using android::idmap2::PrettyPrintVisitor;
using android::idmap2::RawPrintVisitor;
bool Dump(const std::vector<std::string>& args, std::ostream& out_error) {
+ SYSTRACE << "Dump " << args;
std::string idmap_path;
bool verbose;
diff --git a/cmds/idmap2/idmap2/Lookup.cpp b/cmds/idmap2/idmap2/Lookup.cpp
index cfb5dd5b30a9..553d8cac99e4 100644
--- a/cmds/idmap2/idmap2/Lookup.cpp
+++ b/cmds/idmap2/idmap2/Lookup.cpp
@@ -37,6 +37,7 @@
#include "idmap2/CommandLineOptions.h"
#include "idmap2/Idmap.h"
#include "idmap2/Result.h"
+#include "idmap2/SysTrace.h"
#include "idmap2/Xml.h"
#include "idmap2/ZipFile.h"
@@ -156,6 +157,7 @@ Result<std::string> GetTargetPackageNameFromManifest(const std::string& apk_path
} // namespace
bool Lookup(const std::vector<std::string>& args, std::ostream& out_error) {
+ SYSTRACE << "Lookup " << args;
std::vector<std::string> idmap_paths;
std::string config_str;
std::string resid_str;
diff --git a/cmds/idmap2/idmap2/Main.cpp b/cmds/idmap2/idmap2/Main.cpp
index 445fac52f997..a0ffccb26dfe 100644
--- a/cmds/idmap2/idmap2/Main.cpp
+++ b/cmds/idmap2/idmap2/Main.cpp
@@ -24,6 +24,7 @@
#include <vector>
#include "idmap2/CommandLineOptions.h"
+#include "idmap2/SysTrace.h"
#include "Commands.h"
@@ -48,6 +49,7 @@ void PrintUsage(const NameToFunctionMap& commands, std::ostream& out) {
} // namespace
int main(int argc, char** argv) {
+ SYSTRACE << "main";
const NameToFunctionMap commands = {
{"create", Create}, {"dump", Dump}, {"lookup", Lookup}, {"scan", Scan}, {"verify", Verify},
};
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index b1ed42a3e624..873779f386f5 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -30,6 +30,7 @@
#include "idmap2/FileUtils.h"
#include "idmap2/Idmap.h"
#include "idmap2/ResourceUtils.h"
+#include "idmap2/SysTrace.h"
#include "idmap2/Xml.h"
#include "idmap2/ZipFile.h"
@@ -67,6 +68,7 @@ bool VendorIsQOrLater() {
std::unique_ptr<std::vector<std::string>> FindApkFiles(const std::vector<std::string>& dirs,
bool recursive, std::ostream& out_error) {
+ SYSTRACE << "FindApkFiles " << dirs << " " << recursive;
const auto predicate = [](unsigned char type, const std::string& path) -> bool {
static constexpr size_t kExtLen = 4; // strlen(".apk")
return type == DT_REG && path.size() > kExtLen &&
@@ -104,6 +106,7 @@ PolicyBitmask PolicyForPath(const std::string& apk_path) {
} // namespace
bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {
+ SYSTRACE << "Scan " << args;
std::vector<std::string> input_directories;
std::string target_package_name;
std::string target_apk_path;
diff --git a/cmds/idmap2/idmap2/Verify.cpp b/cmds/idmap2/idmap2/Verify.cpp
index 4d4a0e769174..d8fe7aa0ed99 100644
--- a/cmds/idmap2/idmap2/Verify.cpp
+++ b/cmds/idmap2/idmap2/Verify.cpp
@@ -21,11 +21,13 @@
#include "idmap2/CommandLineOptions.h"
#include "idmap2/Idmap.h"
+#include "idmap2/SysTrace.h"
using android::idmap2::CommandLineOptions;
using android::idmap2::IdmapHeader;
bool Verify(const std::vector<std::string>& args, std::ostream& out_error) {
+ SYSTRACE << "Verify " << args;
std::string idmap_path;
const CommandLineOptions opts =
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index f30ce9b08d6e..0e4bd89e355c 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -29,13 +29,13 @@
#include "android-base/stringprintf.h"
#include "binder/IPCThreadState.h"
#include "utils/String8.h"
-#include "utils/Trace.h"
#include "idmap2/BinaryStreamVisitor.h"
#include "idmap2/FileUtils.h"
#include "idmap2/Idmap.h"
#include "idmap2/Policies.h"
#include "idmap2/Result.h"
+#include "idmap2/SysTrace.h"
#include "idmap2d/Idmap2Service.h"
@@ -72,6 +72,7 @@ namespace android::os {
Status Idmap2Service::getIdmapPath(const std::string& overlay_apk_path,
int32_t user_id ATTRIBUTE_UNUSED, std::string* _aidl_return) {
assert(_aidl_return);
+ SYSTRACE << "Idmap2Service::getIdmapPath " << overlay_apk_path;
*_aidl_return = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
return ok();
}
@@ -79,6 +80,7 @@ Status Idmap2Service::getIdmapPath(const std::string& overlay_apk_path,
Status Idmap2Service::removeIdmap(const std::string& overlay_apk_path,
int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) {
assert(_aidl_return);
+ SYSTRACE << "Idmap2Service::removeIdmap " << overlay_apk_path;
const uid_t uid = IPCThreadState::self()->getCallingUid();
const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
if (!UidHasWriteAccessToPath(uid, idmap_path)) {
@@ -98,6 +100,7 @@ Status Idmap2Service::verifyIdmap(const std::string& overlay_apk_path,
int32_t fulfilled_policies ATTRIBUTE_UNUSED,
bool enforce_overlayable ATTRIBUTE_UNUSED,
int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) {
+ SYSTRACE << "Idmap2Service::verifyIdmap " << overlay_apk_path;
assert(_aidl_return);
const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
std::ifstream fin(idmap_path);
@@ -113,15 +116,10 @@ Status Idmap2Service::verifyIdmap(const std::string& overlay_apk_path,
Status Idmap2Service::createIdmap(const std::string& target_apk_path,
const std::string& overlay_apk_path, int32_t fulfilled_policies,
- bool enforce_overlayable, int32_t user_id,
+ bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED,
std::unique_ptr<std::string>* _aidl_return) {
assert(_aidl_return);
- std::stringstream trace;
- trace << __FUNCTION__ << " " << target_apk_path << " " << overlay_apk_path << " "
- << std::to_string(user_id);
- ATRACE_NAME(trace.str().c_str());
- std::cout << trace.str() << std::endl;
-
+ SYSTRACE << "Idmap2Service::createIdmap " << target_apk_path << " " << overlay_apk_path;
_aidl_return->reset(nullptr);
const PolicyBitmask policy_bitmask = ConvertAidlArgToPolicyBitmask(fulfilled_policies);
diff --git a/cmds/idmap2/include/idmap2/SysTrace.h b/cmds/idmap2/include/idmap2/SysTrace.h
new file mode 100644
index 000000000000..19b4353def18
--- /dev/null
+++ b/cmds/idmap2/include/idmap2/SysTrace.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2018 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 IDMAP2_INCLUDE_IDMAP2_SYSTRACE_H_
+#define IDMAP2_INCLUDE_IDMAP2_SYSTRACE_H_
+
+#define ATRACE_TAG ATRACE_TAG_RRO
+
+#include <sstream>
+#include <vector>
+
+#include "cutils/trace.h"
+
+namespace android::idmap2::utils {
+#ifdef __ANDROID__
+
+class ScopedTraceNoStart {
+ public:
+ ~ScopedTraceNoStart() {
+ ATRACE_END();
+ }
+};
+
+class ScopedTraceMessageHelper {
+ public:
+ ~ScopedTraceMessageHelper() {
+ ATRACE_BEGIN(buffer_.str().c_str());
+ }
+
+ std::ostream& stream() {
+ return buffer_;
+ }
+
+ private:
+ std::ostringstream buffer_;
+};
+
+#define SYSTRACE \
+ android::idmap2::utils::ScopedTraceNoStart _trace##__LINE__; \
+ (ATRACE_ENABLED()) && android::idmap2::utils::ScopedTraceMessageHelper().stream()
+
+#else
+
+class DummyStream {
+ public:
+ std::ostream& stream() {
+ return buffer_;
+ }
+
+ private:
+ std::ostringstream buffer_;
+};
+
+#define SYSTRACE android::idmap2::utils::DummyStream().stream()
+
+#endif
+} // namespace android::idmap2::utils
+
+template <typename T>
+std::ostream& operator<<(std::ostream& stream, const std::vector<T>& vector) {
+ bool first = true;
+ stream << "[";
+ for (const auto& item : vector) {
+ if (!first) {
+ stream << ", ";
+ }
+ stream << item;
+ first = false;
+ }
+ stream << "]";
+ return stream;
+}
+
+#endif // IDMAP2_INCLUDE_IDMAP2_SYSTRACE_H_
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index b19d7a971cb8..99b5f0ff3c2d 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -34,6 +34,7 @@
#include "idmap2/Idmap.h"
#include "idmap2/ResourceUtils.h"
#include "idmap2/Result.h"
+#include "idmap2/SysTrace.h"
#include "idmap2/ZipFile.h"
namespace android::idmap2 {
@@ -258,6 +259,7 @@ std::string Idmap::CanonicalIdmapPathFor(const std::string& absolute_dir,
std::unique_ptr<const Idmap> Idmap::FromBinaryStream(std::istream& stream,
std::ostream& out_error) {
+ SYSTRACE << "Idmap::FromBinaryStream";
std::unique_ptr<Idmap> idmap(new Idmap());
idmap->header_ = IdmapHeader::FromBinaryStream(stream);
@@ -304,6 +306,7 @@ std::unique_ptr<const Idmap> Idmap::FromApkAssets(
const std::string& target_apk_path, const ApkAssets& target_apk_assets,
const std::string& overlay_apk_path, const ApkAssets& overlay_apk_assets,
const PolicyBitmask& fulfilled_policies, bool enforce_overlayable, std::ostream& out_error) {
+ SYSTRACE << "Idmap::FromApkAssets";
AssetManager2 target_asset_manager;
if (!target_asset_manager.SetApkAssets({&target_apk_assets}, true, false)) {
out_error << "error: failed to create target asset manager" << std::endl;
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index d6f045ea43fd..f4086557870d 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -71,10 +71,12 @@ cc_defaults {
"src/external/Perfetto.cpp",
"src/external/Perfprofd.cpp",
"src/external/StatsPuller.cpp",
+ "src/external/StatsCallbackPuller.cpp",
"src/external/StatsCompanionServicePuller.cpp",
"src/external/SubsystemSleepStatePuller.cpp",
"src/external/PowerStatsPuller.cpp",
"src/external/ResourceHealthManagerPuller.cpp",
+ "src/external/TrainInfoPuller.cpp",
"src/external/StatsPullerManager.cpp",
"src/external/puller_util.cpp",
"src/logd/LogEvent.cpp",
@@ -237,6 +239,7 @@ cc_test {
"tests/guardrail/StatsdStats_test.cpp",
"tests/metrics/metrics_test_helper.cpp",
"tests/statsd_test_util.cpp",
+ "tests/storage/StorageManager_test.cpp",
"tests/e2e/WakelockDuration_e2e_test.cpp",
"tests/e2e/MetricActivation_e2e_test.cpp",
"tests/e2e/MetricConditionLink_e2e_test.cpp",
diff --git a/cmds/statsd/benchmark/metric_util.cpp b/cmds/statsd/benchmark/metric_util.cpp
index 067b6eddf254..cca6d525ea16 100644
--- a/cmds/statsd/benchmark/metric_util.cpp
+++ b/cmds/statsd/benchmark/metric_util.cpp
@@ -367,7 +367,8 @@ sp<StatsLogProcessor> CreateStatsLogProcessor(const long timeBaseSec, const Stat
sp<AlarmMonitor> periodicAlarmMonitor;
sp<StatsLogProcessor> processor =
new StatsLogProcessor(uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec * NS_PER_SEC, [](const ConfigKey&) { return true; });
+ timeBaseSec * NS_PER_SEC, [](const ConfigKey&) { return true; },
+ [](const int&, const vector<int64_t>&) { return true; });
processor->OnConfigUpdated(timeBaseSec * NS_PER_SEC, key, config);
return processor;
}
@@ -393,4 +394,4 @@ int64_t StringToId(const string& str) {
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 250f5bfd0685..653ef2ec9869 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -88,12 +88,15 @@ StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
const sp<AlarmMonitor>& periodicAlarmMonitor,
const int64_t timeBaseNs,
- const std::function<bool(const ConfigKey&)>& sendBroadcast)
+ const std::function<bool(const ConfigKey&)>& sendBroadcast,
+ const std::function<bool(
+ const int&, const vector<int64_t>&)>& activateBroadcast)
: mUidMap(uidMap),
mPullerManager(pullerManager),
mAnomalyAlarmMonitor(anomalyAlarmMonitor),
mPeriodicAlarmMonitor(periodicAlarmMonitor),
mSendBroadcast(sendBroadcast),
+ mSendActivationBroadcast(activateBroadcast),
mTimeBaseNs(timeBaseNs),
mLargestTimestampSeen(0),
mLastTimestampSeen(0) {
@@ -223,11 +226,73 @@ void StatsLogProcessor::OnLogEvent(LogEvent* event) {
mapIsolatedUidToHostUidIfNecessaryLocked(event);
}
+ std::unordered_set<int> uidsWithActiveConfigsChanged;
+ std::unordered_map<int, std::vector<int64_t>> activeConfigsPerUid;
// pass the event to metrics managers.
for (auto& pair : mMetricsManagers) {
+ int uid = pair.first.GetUid();
+ int64_t configId = pair.first.GetId();
+ bool isPrevActive = pair.second->isActive();
pair.second->onLogEvent(*event);
+ bool isCurActive = pair.second->isActive();
+ // Map all active configs by uid.
+ if (isCurActive) {
+ auto activeConfigs = activeConfigsPerUid.find(uid);
+ if (activeConfigs != activeConfigsPerUid.end()) {
+ activeConfigs->second.push_back(configId);
+ } else {
+ vector<int64_t> newActiveConfigs;
+ newActiveConfigs.push_back(configId);
+ activeConfigsPerUid[uid] = newActiveConfigs;
+ }
+ }
+ // The activation state of this config changed.
+ if (isPrevActive != isCurActive) {
+ VLOG("Active status changed for uid %d", uid);
+ uidsWithActiveConfigsChanged.insert(uid);
+ StatsdStats::getInstance().noteActiveStatusChanged(pair.first, isCurActive);
+ }
flushIfNecessaryLocked(event->GetElapsedTimestampNs(), pair.first, *(pair.second));
}
+
+ for (int uid : uidsWithActiveConfigsChanged) {
+ // Send broadcast so that receivers can pull data.
+ auto lastBroadcastTime = mLastActivationBroadcastTimes.find(uid);
+ if (lastBroadcastTime != mLastActivationBroadcastTimes.end()) {
+ if (currentTimestampNs - lastBroadcastTime->second <
+ StatsdStats::kMinActivationBroadcastPeriodNs) {
+ VLOG("StatsD would've sent an activation broadcast but the rate limit stopped us.");
+ return;
+ }
+ }
+ auto activeConfigs = activeConfigsPerUid.find(uid);
+ if (activeConfigs != activeConfigsPerUid.end()) {
+ if (mSendActivationBroadcast(uid, activeConfigs->second)) {
+ VLOG("StatsD sent activation notice for uid %d", uid);
+ mLastActivationBroadcastTimes[uid] = currentTimestampNs;
+ }
+ } else {
+ std::vector<int64_t> emptyActiveConfigs;
+ if (mSendActivationBroadcast(uid, emptyActiveConfigs)) {
+ VLOG("StatsD sent EMPTY activation notice for uid %d", uid);
+ mLastActivationBroadcastTimes[uid] = currentTimestampNs;
+ }
+ }
+ }
+}
+
+void StatsLogProcessor::GetActiveConfigs(const int uid, vector<int64_t>& outActiveConfigs) {
+ std::lock_guard<std::mutex> lock(mMetricsMutex);
+ GetActiveConfigsLocked(uid, outActiveConfigs);
+}
+
+void StatsLogProcessor::GetActiveConfigsLocked(const int uid, vector<int64_t>& outActiveConfigs) {
+ outActiveConfigs.clear();
+ for (auto& pair : mMetricsManagers) {
+ if (pair.first.GetUid() == uid && pair.second->isActive()) {
+ outActiveConfigs.push_back(pair.first.GetId());
+ }
+ }
}
void StatsLogProcessor::OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
@@ -444,6 +509,18 @@ void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {
mLastBroadcastTimes.erase(key);
+ int uid = key.GetUid();
+ bool lastConfigForUid = true;
+ for (auto it : mMetricsManagers) {
+ if (it.first.GetUid() == uid) {
+ lastConfigForUid = false;
+ break;
+ }
+ }
+ if (lastConfigForUid) {
+ mLastActivationBroadcastTimes.erase(uid);
+ }
+
if (mMetricsManagers.empty()) {
mPullerManager->ForceClearPullerCache();
}
@@ -526,9 +603,10 @@ void StatsLogProcessor::WriteMetricsActivationToDisk(int64_t currentTimeNs) {
proto.write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_ID, (long long)pair.first.GetId());
proto.write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_UID, pair.first.GetUid());
- vector<const MetricProducer*> acrtiveMetrics;
- pair.second->getActiveMetrics(acrtiveMetrics);
- for (const MetricProducer* metric : acrtiveMetrics) {
+ vector<MetricProducer*> activeMetrics;
+ pair.second->prepForShutDown(currentTimeNs);
+ pair.second->getActiveMetrics(activeMetrics);
+ for (MetricProducer* metric : activeMetrics) {
if (metric->isActive()) {
uint64_t metricToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
FIELD_ID_ACTIVE_METRIC);
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 77d9a2f5f418..ea9c6e704017 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -49,7 +49,9 @@ public:
const sp<AlarmMonitor>& anomalyAlarmMonitor,
const sp<AlarmMonitor>& subscriberTriggerAlarmMonitor,
const int64_t timeBaseNs,
- const std::function<bool(const ConfigKey&)>& sendBroadcast);
+ const std::function<bool(const ConfigKey&)>& sendBroadcast,
+ const std::function<bool(const int&,
+ const vector<int64_t>&)>& sendActivationBroadcast);
virtual ~StatsLogProcessor();
void OnLogEvent(LogEvent* event);
@@ -60,6 +62,8 @@ public:
size_t GetMetricsSize(const ConfigKey& key) const;
+ void GetActiveConfigs(const int uid, vector<int64_t>& outActiveConfigs);
+
void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs,
const bool include_current_partial_bucket, const bool erase_data,
const DumpReportReason dumpReportReason, vector<uint8_t>* outData);
@@ -125,6 +129,9 @@ private:
std::unordered_map<ConfigKey, long> mLastBroadcastTimes;
+ // Last time we sent a broadcast to this uid that the active configs had changed.
+ std::unordered_map<int, long> mLastActivationBroadcastTimes;
+
// Tracks when we last checked the bytes consumed for each config key.
std::unordered_map<ConfigKey, long> mLastByteSizeTimes;
@@ -144,6 +151,8 @@ private:
void OnConfigUpdatedLocked(
const int64_t currentTimestampNs, const ConfigKey& key, const StatsdConfig& config);
+ void GetActiveConfigsLocked(const int uid, vector<int64_t>& outActiveConfigs);
+
void WriteDataToDiskLocked(const DumpReportReason dumpReportReason);
void WriteDataToDiskLocked(const ConfigKey& key, const int64_t timestampNs,
const DumpReportReason dumpReportReason);
@@ -174,6 +183,10 @@ private:
// to retrieve the stored data.
std::function<bool(const ConfigKey& key)> mSendBroadcast;
+ // Function used to send a broadcast so that receiver can be notified of which configs
+ // are currently active.
+ std::function<bool(const int& uid, const vector<int64_t>& configIds)> mSendActivationBroadcast;
+
const int64_t mTimeBaseNs;
// Largest timestamp of the events that we have processed.
@@ -195,6 +208,7 @@ private:
FRIEND_TEST(StatsLogProcessorTest, TestRateLimitBroadcast);
FRIEND_TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge);
FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
+ FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1);
FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 86bf3eca3ee6..fb603b9ce163 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -31,6 +31,7 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/PermissionController.h>
+#include <cutils/multiuser.h>
#include <dirent.h>
#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
#include <private/android_filesystem_config.h>
@@ -47,6 +48,7 @@ using namespace android;
using android::base::StringPrintf;
using android::util::FIELD_COUNT_REPEATED;
+using android::util::FIELD_TYPE_INT64;
using android::util::FIELD_TYPE_MESSAGE;
namespace android {
@@ -62,6 +64,8 @@ constexpr const char* kOpUsage = "android:get_usage_stats";
// for StatsDataDumpProto
const int FIELD_ID_REPORTS_LIST = 1;
+// for TrainInfo experiment id serialization
+const int FIELD_ID_EXPERIMENT_ID = 1;
static binder::Status ok() {
return binder::Status::ok();
@@ -176,6 +180,21 @@ StatsService::StatsService(const sp<Looper>& handlerLooper)
sc->sendDataBroadcast(receiver, mProcessor->getLastReportTimeNs(key));
return true;
}
+ },
+ [this](const int& uid, const vector<int64_t>& activeConfigs) {
+ auto receiver = mConfigManager->GetActiveConfigsChangedReceiver(uid);
+ sp<IStatsCompanionService> sc = getStatsCompanionService();
+ if (sc == nullptr) {
+ VLOG("Could not access statsCompanion");
+ return false;
+ } else if (receiver == nullptr) {
+ VLOG("Could not find receiver for uid %d", uid);
+ return false;
+ } else {
+ sc->sendActiveConfigsChangedBroadcast(receiver, activeConfigs);
+ VLOG("StatsService::active configs broadcast succeeded for uid %d" , uid);
+ return true;
+ }
});
mConfigManager->AddListener(mProcessor);
@@ -357,6 +376,9 @@ status_t StatsService::command(int in, int out, int err, Vector<String8>& args,
if (!args[0].compare(String8("print-logs"))) {
return cmd_print_logs(out, args);
}
+ if (!args[0].compare(String8("send-active-configs"))) {
+ return cmd_trigger_active_config_broadcast(out, args);
+ }
if (!args[0].compare(String8("data-subscribe"))) {
if (mShellSubscriber == nullptr) {
mShellSubscriber = new ShellSubscriber(mUidMap, mPullerManager);
@@ -449,6 +471,19 @@ void StatsService::print_cmd_help(int out) {
dprintf(out, " NAME The name of the configuration\n");
dprintf(out, "\n");
dprintf(out, "\n");
+ dprintf(out,
+ "usage: adb shell cmd stats send-active-configs [--uid=UID] [--configs] "
+ "[NAME1] [NAME2] [NAME3..]\n");
+ dprintf(out, " Send a broadcast that informs the subscriber of the current active configs.\n");
+ dprintf(out, " --uid=UID The uid of the configurations. It is only possible to pass\n");
+ dprintf(out, " the UID parameter on eng builds. If UID is omitted the\n");
+ dprintf(out, " calling uid is used.\n");
+ dprintf(out, " --configs Send the list of configs in the name list instead of\n");
+ dprintf(out, " the currently active configs\n");
+ dprintf(out, " NAME LIST List of configuration names to be included in the broadcast.\n");
+
+ dprintf(out, "\n");
+ dprintf(out, "\n");
dprintf(out, "usage: adb shell cmd stats print-stats\n");
dprintf(out, " Prints some basic stats.\n");
dprintf(out, " --proto Print proto binary instead of string format.\n");
@@ -499,6 +534,59 @@ status_t StatsService::cmd_trigger_broadcast(int out, Vector<String8>& args) {
return NO_ERROR;
}
+status_t StatsService::cmd_trigger_active_config_broadcast(int out, Vector<String8>& args) {
+ const int argCount = args.size();
+ int uid;
+ vector<int64_t> configIds;
+ if (argCount == 1) {
+ // Automatically pick the uid and send a broadcast that has no active configs.
+ uid = IPCThreadState::self()->getCallingUid();
+ mProcessor->GetActiveConfigs(uid, configIds);
+ } else {
+ int curArg = 1;
+ if(args[curArg].find("--uid=") == 0) {
+ string uidArgStr(args[curArg].c_str());
+ string uidStr = uidArgStr.substr(6);
+ if (!getUidFromString(uidStr.c_str(), uid)) {
+ dprintf(out, "Invalid UID. Note that the config can only be set for "
+ "other UIDs on eng or userdebug builds.\n");
+ return UNKNOWN_ERROR;
+ }
+ curArg++;
+ } else {
+ uid = IPCThreadState::self()->getCallingUid();
+ }
+ if (curArg == argCount || args[curArg] != "--configs") {
+ VLOG("Reached end of args, or specify configs not set. Sending actual active configs,");
+ mProcessor->GetActiveConfigs(uid, configIds);
+ } else {
+ // Flag specified, use the given list of configs.
+ curArg++;
+ for (int i = curArg; i < argCount; i++) {
+ char* endp;
+ int64_t configID = strtoll(args[i].c_str(), &endp, 10);
+ if (endp == args[i].c_str() || *endp != '\0') {
+ dprintf(out, "Error parsing config ID.\n");
+ return UNKNOWN_ERROR;
+ }
+ VLOG("Adding config id %ld", static_cast<long>(configID));
+ configIds.push_back(configID);
+ }
+ }
+ }
+ auto receiver = mConfigManager->GetActiveConfigsChangedReceiver(uid);
+ sp<IStatsCompanionService> sc = getStatsCompanionService();
+ if (sc == nullptr) {
+ VLOG("Could not access statsCompanion");
+ } else if (receiver == nullptr) {
+ VLOG("Could not find receiver for uid %d", uid);
+ } else {
+ sc->sendActiveConfigsChangedBroadcast(receiver, configIds);
+ VLOG("StatsService::trigger active configs changed broadcast succeeded for uid %d" , uid);
+ }
+ return NO_ERROR;
+}
+
status_t StatsService::cmd_config(int in, int out, int err, Vector<String8>& args) {
const int argCount = args.size();
if (argCount >= 2) {
@@ -762,7 +850,10 @@ status_t StatsService::cmd_print_logs(int out, const Vector<String8>& args) {
}
bool StatsService::getUidFromArgs(const Vector<String8>& args, size_t uidArgIndex, int32_t& uid) {
- const char* s = args[uidArgIndex].c_str();
+ return getUidFromString(args[uidArgIndex].c_str(), uid);
+}
+
+bool StatsService::getUidFromString(const char* s, int32_t& uid) {
if (*s == '\0') {
return false;
}
@@ -998,8 +1089,13 @@ Status StatsService::setActiveConfigsChangedOperation(const sp<android::IBinder>
ENFORCE_DUMP_AND_USAGE_STATS(packageName);
IPCThreadState* ipc = IPCThreadState::self();
- mConfigManager->SetActiveConfigsChangedReceiver(ipc->getCallingUid(), intentSender);
- //TODO: Return the list of configs that are already active
+ int uid = ipc->getCallingUid();
+ mConfigManager->SetActiveConfigsChangedReceiver(uid, intentSender);
+ if (output != nullptr) {
+ mProcessor->GetActiveConfigs(uid, *output);
+ } else {
+ ALOGW("StatsService::setActiveConfigsChanged output was nullptr");
+ }
return Status::ok();
}
@@ -1057,6 +1153,74 @@ Status StatsService::sendAppBreadcrumbAtom(int32_t label, int32_t state) {
return Status::ok();
}
+Status StatsService::registerPullerCallback(int32_t atomTag,
+ const sp<android::os::IStatsPullerCallback>& pullerCallback,
+ const String16& packageName) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
+ VLOG("StatsService::registerPullerCallback called.");
+ mPullerManager->RegisterPullerCallback(atomTag, pullerCallback);
+ return Status::ok();
+}
+
+Status StatsService::unregisterPullerCallback(int32_t atomTag, const String16& packageName) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
+ VLOG("StatsService::unregisterPullerCallback called.");
+ mPullerManager->UnregisterPullerCallback(atomTag);
+ return Status::ok();
+}
+
+Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& trainName,
+ int64_t trainVersionCode, int options,
+ int32_t state,
+ const std::vector<int64_t>& experimentIds) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ // For testing
+ if (uid == AID_ROOT || uid == AID_SYSTEM || uid == AID_SHELL) {
+ return ok();
+ }
+
+ // Caller must be granted these permissions
+ if (!checkCallingPermission(String16(kPermissionDump))) {
+ return exception(binder::Status::EX_SECURITY,
+ StringPrintf("UID %d lacks permission %s", uid, kPermissionDump));
+ }
+ if (!checkCallingPermission(String16(kPermissionUsage))) {
+ return exception(binder::Status::EX_SECURITY,
+ StringPrintf("UID %d lacks permission %s", uid, kPermissionUsage));
+ }
+ // TODO: add verifier permission
+
+ userid_t userId = multiuser_get_user_id(uid);
+
+ bool requiresStaging = options | IStatsManager::FLAG_REQUIRE_STAGING;
+ bool rollbackEnabled = options | IStatsManager::FLAG_ROLLBACK_ENABLED;
+ bool requiresLowLatencyMonitor = options | IStatsManager::FLAG_REQUIRE_LOW_LATENCY_MONITOR;
+
+ ProtoOutputStream proto;
+ for (const auto& expId : experimentIds) {
+ proto.write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_EXPERIMENT_ID,
+ (long long)expId);
+ }
+
+ vector<uint8_t> buffer;
+ buffer.resize(proto.size());
+ size_t pos = 0;
+ auto iter = proto.data();
+ while (iter.readBuffer() != NULL) {
+ size_t toRead = iter.currentToRead();
+ std::memcpy(&(buffer[pos]), iter.readBuffer(), toRead);
+ pos += toRead;
+ iter.rp()->move(toRead);
+ }
+ LogEvent event(std::string(String8(trainName).string()), trainVersionCode, requiresStaging,
+ rollbackEnabled, requiresLowLatencyMonitor, state, buffer, userId);
+ mProcessor->OnLogEvent(&event);
+ StorageManager::writeTrainInfo(trainVersionCode, buffer);
+ return Status::ok();
+}
+
hardware::Return<void> StatsService::reportSpeakerImpedance(
const SpeakerImpedance& speakerImpedance) {
LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), speakerImpedance);
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index cdff50fcb62e..d24565a63054 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -31,6 +31,7 @@
#include <android/frameworks/stats/1.0/types.h>
#include <android/os/BnStatsManager.h>
#include <android/os/IStatsCompanionService.h>
+#include <android/os/IStatsManager.h>
#include <binder/IResultReceiver.h>
#include <utils/Looper.h>
@@ -173,6 +174,26 @@ public:
virtual Status sendAppBreadcrumbAtom(int32_t label, int32_t state) override;
/**
+ * Binder call to register a callback function for a vendor pulled atom.
+ * Note: this atom must NOT have uid as a field.
+ */
+ virtual Status registerPullerCallback(int32_t atomTag,
+ const sp<android::os::IStatsPullerCallback>& pullerCallback,
+ const String16& packageName) override;
+
+ /**
+ * Binder call to unregister any existing callback function for a vendor pulled atom.
+ */
+ virtual Status unregisterPullerCallback(int32_t atomTag, const String16& packageName) override;
+
+ /**
+ * Binder call to log BinaryPushStateChanged atom.
+ */
+ virtual Status sendBinaryPushStateChangedAtom(
+ const android::String16& trainName, int64_t trainVersionCode, int options,
+ int32_t state, const std::vector<int64_t>& experimentIds) override;
+
+ /**
* Binder call to get SpeakerImpedance atom.
*/
virtual Return<void> reportSpeakerImpedance(const SpeakerImpedance& speakerImpedance) override;
@@ -262,6 +283,12 @@ private:
*/
status_t cmd_trigger_broadcast(int outFd, Vector<String8>& args);
+
+ /**
+ * Trigger an active configs changed broadcast.
+ */
+ status_t cmd_trigger_active_config_broadcast(int outFd, Vector<String8>& args);
+
/**
* Handle the config sub-command.
*/
@@ -328,6 +355,15 @@ private:
bool getUidFromArgs(const Vector<String8>& args, size_t uidArgIndex, int32_t& uid);
/**
+ * Writes the value of uidSting into uid.
+ * Returns whether the uid is reasonable (type uid_t) and whether
+ * 1. it is equal to the calling uid, or
+ * 2. the device is mEngBuild, or
+ * 3. the caller is AID_ROOT and the uid is AID_SHELL (i.e. ROOT can impersonate SHELL).
+ */
+ bool getUidFromString(const char* uidString, int32_t& uid);
+
+ /**
* Adds a configuration after checking permissions and obtaining UID from binder call.
*/
bool addConfigurationChecked(int uid, int64_t key, const vector<uint8_t>& config);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index d0974d6e3398..873b772d06ea 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -31,6 +31,7 @@ import "frameworks/base/core/proto/android/bluetooth/hfp/enums.proto";
import "frameworks/base/core/proto/android/bluetooth/smp/enums.proto";
import "frameworks/base/core/proto/android/debug/enums.proto";
import "frameworks/base/core/proto/android/hardware/biometrics/enums.proto";
+import "frameworks/base/core/proto/android/hardware/sensor/assist/enums.proto";
import "frameworks/base/core/proto/android/net/networkcapabilities.proto";
import "frameworks/base/core/proto/android/os/enums.proto";
import "frameworks/base/core/proto/android/server/connectivity/data_stall_event.proto";
@@ -215,7 +216,7 @@ message Atom {
SpeechDspStatReported speech_dsp_stat_reported = 145;
UsbContaminantReported usb_contaminant_reported = 146;
WatchdogRollbackOccurred watchdog_rollback_occurred = 147;
- BiometricHalDeathReported biometric_hal_death_reported = 148;
+ BiometricSystemHealthIssueDetected biometric_system_health_issue_detected = 148;
BubbleUIChanged bubble_ui_changed = 149;
ScheduledJobConstraintChanged scheduled_job_constraint_changed = 150;
BluetoothActiveDeviceChanged bluetooth_active_device_changed = 151;
@@ -241,6 +242,9 @@ message Atom {
BluetoothSocketConnectionStateChanged bluetooth_socket_connection_state_changed = 171;
DeviceIdentifierAccessDenied device_identifier_access_denied = 172;
BubbleDeveloperErrorReported bubble_developer_error_reported = 173;
+ AssistGestureStageReported assist_gesture_stage_reported = 174;
+ AssistGestureFeedbackReported assist_gesture_feedback_reported = 175;
+ AssistGestureProgressReported assist_gesture_progress_reported = 176;
}
// Pulled events will start at field 10000.
@@ -297,6 +301,7 @@ message Atom {
NumBiometricsEnrolled num_faces_enrolled = 10048;
RoleHolder role_holder = 10049;
DangerousPermissionState dangerous_permission_state = 10050;
+ TrainInfo train_info = 10051;
}
// DO NOT USE field numbers above 100,000 in AOSP.
@@ -2086,9 +2091,9 @@ message BluetoothSocketConnectionStateChanged {
// Salt: Randomly generated 256 bit value
// Hash algorithm: HMAC-SHA256
// Size: 32 byte
- // Default: null or empty if the device identifier is not known
+ // Default: null or empty if this is a server listener socket
optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
- // Port of this socket
+ // Temporary port of this socket for the current connection or session only
// Default 0 when unknown or don't care
optional int32 port = 2;
// Socket type as mentioned in
@@ -2102,6 +2107,14 @@ message BluetoothSocketConnectionStateChanged {
optional int64 tx_bytes = 5;
// Number of bytes received from remote device during this connection
optional int64 rx_bytes = 6;
+ // Socket owner's UID
+ optional int32 uid = 7 [(is_uid) = true];
+ // Server port of this socket, if any. When both |server_port| and |port| fields are populated,
+ // |port| must be spawned by |server_port|
+ // Default 0 when unknown or don't care
+ optional int32 server_port = 8;
+ // Whether this is a server listener socket
+ optional android.bluetooth.SocketRoleEnum is_server = 9;
}
/**
@@ -2168,6 +2181,7 @@ message HardwareFailed {
SPEAKER_SHORT = 3;
FINGERPRINT_SENSOR_BROKEN = 4;
FINGERPRINT_TOO_MANY_DEAD_PIXELS = 5;
+ DEGRADE = 6;
}
optional int32 failure_code = 3;
}
@@ -3050,13 +3064,15 @@ message BiometricErrorOccurred {
}
/**
- * Logs when a biometric HAL has crashed.
+ * Logs when a system health issue is detected.
* Logged from:
* frameworks/base/services/core/java/com/android/server/biometrics
*/
-message BiometricHalDeathReported {
+message BiometricSystemHealthIssueDetected {
// Biometric modality.
optional android.hardware.biometrics.ModalityEnum modality = 1;
+ // Type of issue detected.
+ optional android.hardware.biometrics.IssueEnum issue = 2;
}
message Notification {
@@ -3140,6 +3156,13 @@ message FlagFlipUpdateOccurred {
optional int64 order_id = 2;
}
+/**
+ * Potential experiment ids that goes with a train install.
+ */
+message TrainExperimentIds {
+ repeated int64 experiment_id = 1;
+}
+
/*
* Logs when a binary push state changes.
* Logged by the installer via public api.
@@ -3166,8 +3189,14 @@ message BinaryPushStateChanged {
INSTALL_FAILURE = 6;
INSTALL_CANCELLED = 7;
INSTALLER_ROLLBACK_REQUESTED = 8;
+ INSTALLER_ROLLBACK_SUCCESS = 9;
+ INSTALLER_ROLLBACK_FAILURE = 10;
}
optional State state = 6;
+ // Possible experiment ids for monitoring this push.
+ optional TrainExperimentIds experiment_ids = 7 [(log_mode) = MODE_BYTES];
+ // user id
+ optional int32 user_id = 8;
}
/** Represents USB port overheat event. */
@@ -5493,3 +5522,45 @@ message DeviceIdentifierAccessDenied {
// True if the package is privileged.
optional bool is_priv_app = 4;
}
+
+/**
+ * Pulls the ongoing mainline install train version code.
+ * Pulled from StatsCompanionService
+ */
+message TrainInfo {
+ optional int64 train_version_code = 1;
+
+ optional TrainExperimentIds train_experiment_id = 2;
+}
+
+/**
+ * Logs the gesture stage changed event.
+ *
+ * Logged from:
+ * frameworks/base/packages/SystemUI/
+ */
+message AssistGestureStageReported {
+ optional android.hardware.sensor.assist.AssistGestureStageEnum gesture_stage = 1;
+}
+
+/**
+ * Logs the feedback type.
+ *
+ * Logged from:
+ * frameworks/base/packages/SystemUI/
+ */
+message AssistGestureFeedbackReported {
+ // Whether or not the gesture was used.
+ optional android.hardware.sensor.assist.AssistGestureFeedbackEnum feedback_type = 1;
+}
+
+/**
+ * Logs the progress.
+ *
+ * Logged from:
+ * frameworks/base/packages/SystemUI/
+ */
+message AssistGestureProgressReported {
+ // [0,100] progress for the assist gesture.
+ optional int32 progress = 1;
+}
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index aa22333ab26c..fc949b494194 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -144,10 +144,20 @@ void ConfigManager::RemoveConfig(const ConfigKey& key) {
{
lock_guard <mutex> lock(mMutex);
- auto uidIt = mConfigs.find(key.GetUid());
+ auto uid = key.GetUid();
+ auto uidIt = mConfigs.find(uid);
if (uidIt != mConfigs.end() && uidIt->second.find(key) != uidIt->second.end()) {
// Remove from map
uidIt->second.erase(key);
+
+ // No more configs for this uid, lets remove the active configs callback.
+ if (uidIt->second.empty()) {
+ auto itActiveConfigsChangedReceiver = mActiveConfigsChangedReceivers.find(uid);
+ if (itActiveConfigsChangedReceiver != mActiveConfigsChangedReceivers.end()) {
+ mActiveConfigsChangedReceivers.erase(itActiveConfigsChangedReceiver);
+ }
+ }
+
for (const sp<ConfigListener>& listener : mListeners) {
broadcastList.push_back(listener);
}
diff --git a/cmds/statsd/src/external/StatsCallbackPuller.cpp b/cmds/statsd/src/external/StatsCallbackPuller.cpp
new file mode 100644
index 000000000000..d718273e9b85
--- /dev/null
+++ b/cmds/statsd/src/external/StatsCallbackPuller.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define DEBUG false // STOPSHIP if true
+#include "Log.h"
+
+#include <android/os/IStatsPullerCallback.h>
+
+#include "StatsCallbackPuller.h"
+#include "logd/LogEvent.h"
+#include "stats_log_util.h"
+
+using namespace android::binder;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+StatsCallbackPuller::StatsCallbackPuller(int tagId, const sp<IStatsPullerCallback>& callback) :
+ StatsPuller(tagId), mCallback(callback) {
+ VLOG("StatsCallbackPuller created for tag %d", tagId);
+}
+
+bool StatsCallbackPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
+ VLOG("StatsCallbackPuller called for tag %d", mTagId)
+ if(mCallback == nullptr) {
+ ALOGW("No callback registered");
+ return false;
+ }
+ int64_t wallClockTimeNs = getWallClockNs();
+ int64_t elapsedTimeNs = getElapsedRealtimeNs();
+ vector<StatsLogEventWrapper> returned_value;
+ Status status = mCallback->pullData(mTagId, elapsedTimeNs, wallClockTimeNs, &returned_value);
+ if (!status.isOk()) {
+ ALOGW("StatsCallbackPuller::pull failed for %d", mTagId);
+ return false;
+ }
+ data->clear();
+ for (const StatsLogEventWrapper& it: returned_value) {
+ LogEvent::createLogEvents(it, *data);
+ }
+ VLOG("StatsCallbackPuller::pull succeeded for %d", mTagId);
+ return true;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/StatsCallbackPuller.h b/cmds/statsd/src/external/StatsCallbackPuller.h
new file mode 100644
index 000000000000..c4bfa89ba9a7
--- /dev/null
+++ b/cmds/statsd/src/external/StatsCallbackPuller.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/os/IStatsPullerCallback.h>
+#include <utils/String16.h>
+#include "StatsPuller.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class StatsCallbackPuller : public StatsPuller {
+public:
+ explicit StatsCallbackPuller(int tagId, const sp<IStatsPullerCallback>& callback);
+
+private:
+ bool PullInternal(vector<std::shared_ptr<LogEvent> >* data) override;
+ const sp<IStatsPullerCallback> mCallback;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp
index c7c22ee85f0f..9552c0a5e35e 100644
--- a/cmds/statsd/src/external/StatsPuller.cpp
+++ b/cmds/statsd/src/external/StatsPuller.cpp
@@ -33,7 +33,7 @@ sp<UidMap> StatsPuller::mUidMap = nullptr;
void StatsPuller::SetUidMap(const sp<UidMap>& uidMap) { mUidMap = uidMap; }
StatsPuller::StatsPuller(const int tagId)
- : mTagId(tagId) {
+ : mTagId(tagId), mLastPullTimeNs(0) {
}
bool StatsPuller::Pull(std::vector<std::shared_ptr<LogEvent>>* data) {
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index ecdcd21d44dd..98f810fd9a2c 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -18,6 +18,7 @@
#include "Log.h"
#include <android/os/IStatsCompanionService.h>
+#include <android/os/IStatsPullerCallback.h>
#include <cutils/log.h>
#include <math.h>
#include <stdint.h>
@@ -28,9 +29,11 @@
#include "../statscompanion_util.h"
#include "PowerStatsPuller.h"
#include "ResourceHealthManagerPuller.h"
+#include "StatsCallbackPuller.h"
#include "StatsCompanionServicePuller.h"
#include "StatsPullerManager.h"
#include "SubsystemSleepStatePuller.h"
+#include "TrainInfoPuller.h"
#include "statslog.h"
#include <iostream>
@@ -49,7 +52,7 @@ namespace statsd {
// Values smaller than this may require to update the alarm.
const int64_t NO_ALARM_UPDATE = INT64_MAX;
-const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
+std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
// wifi_bytes_transfer
{android::util::WIFI_BYTES_TRANSFER,
{.additiveFields = {2, 3, 4, 5},
@@ -150,7 +153,7 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_HIGH_WATER_MARK)}},
// temperature
{android::util::TEMPERATURE,
- {.puller = new StatsCompanionServicePuller(android::util::TEMPERATURE)}},
+ {.puller = new StatsCompanionServicePuller(android::util::TEMPERATURE)}},
// binder_calls
{android::util::BINDER_CALLS,
{.additiveFields = {4, 5, 6, 8, 12},
@@ -229,6 +232,8 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
// PermissionState.
{android::util::DANGEROUS_PERMISSION_STATE,
{.puller = new StatsCompanionServicePuller(android::util::DANGEROUS_PERMISSION_STATE)}},
+ // TrainInfo.
+ {android::util::TRAIN_INFO, {.puller = new TrainInfoPuller()}},
};
StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
@@ -420,6 +425,30 @@ int StatsPullerManager::ClearPullerCacheIfNecessary(int64_t timestampNs) {
return totalCleared;
}
+void StatsPullerManager::RegisterPullerCallback(int32_t atomTag,
+ const sp<IStatsPullerCallback>& callback) {
+ AutoMutex _l(mLock);
+ // Platform pullers cannot be changed.
+ if (atomTag < StatsdStats::kMaxPlatformAtomTag) {
+ VLOG("RegisterPullerCallback: atom tag %d is less than min tag %d",
+ atomTag, StatsdStats::kMaxPlatformAtomTag);
+ return;
+ }
+ VLOG("RegisterPullerCallback: adding puller for tag %d", atomTag);
+ StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/true);
+ kAllPullAtomInfo[atomTag] = {.puller = new StatsCallbackPuller(atomTag, callback)};
+}
+
+void StatsPullerManager::UnregisterPullerCallback(int32_t atomTag) {
+ AutoMutex _l(mLock);
+ // Platform pullers cannot be changed.
+ if (atomTag < StatsdStats::kMaxPlatformAtomTag) {
+ return;
+ }
+ StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/false);
+ kAllPullAtomInfo.erase(atomTag);
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h
index 807e4af03dae..45f6b3568143 100644
--- a/cmds/statsd/src/external/StatsPullerManager.h
+++ b/cmds/statsd/src/external/StatsPullerManager.h
@@ -17,6 +17,7 @@
#pragma once
#include <android/os/IStatsCompanionService.h>
+#include <android/os/IStatsPullerCallback.h>
#include <binder/IServiceManager.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
@@ -91,7 +92,12 @@ public:
void SetStatsCompanionService(sp<IStatsCompanionService> statsCompanionService);
- const static std::map<int, PullAtomInfo> kAllPullAtomInfo;
+ void RegisterPullerCallback(int32_t atomTag,
+ const sp<IStatsPullerCallback>& callback);
+
+ void UnregisterPullerCallback(int32_t atomTag);
+
+ static std::map<int, PullAtomInfo> kAllPullAtomInfo;
private:
sp<IStatsCompanionService> mStatsCompanionService = nullptr;
diff --git a/cmds/statsd/src/external/TrainInfoPuller.cpp b/cmds/statsd/src/external/TrainInfoPuller.cpp
new file mode 100644
index 000000000000..9d0924297912
--- /dev/null
+++ b/cmds/statsd/src/external/TrainInfoPuller.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define DEBUG false // STOPSHIP if true
+#include "Log.h"
+
+#include "external/StatsPuller.h"
+
+#include "TrainInfoPuller.h"
+#include "logd/LogEvent.h"
+#include "stats_log_util.h"
+#include "statslog.h"
+#include "storage/StorageManager.h"
+
+using std::make_shared;
+using std::shared_ptr;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+TrainInfoPuller::TrainInfoPuller() :
+ StatsPuller(android::util::TRAIN_INFO) {
+}
+
+bool TrainInfoPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
+ InstallTrainInfo trainInfo;
+ bool ret = StorageManager::readTrainInfo(trainInfo);
+ if (!ret) {
+ ALOGW("Failed to read train info.");
+ return false;
+ }
+ auto event = make_shared<LogEvent>(getWallClockNs(), getElapsedRealtimeNs(), trainInfo);
+ data->push_back(event);
+ return true;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/media/java/android/media/session/MediaSessionProviderService.java b/cmds/statsd/src/external/TrainInfoPuller.h
index 9a346ff4a12e..615d02351fd3 100644
--- a/media/java/android/media/session/MediaSessionProviderService.java
+++ b/cmds/statsd/src/external/TrainInfoPuller.h
@@ -14,22 +14,25 @@
* limitations under the License.
*/
-package android.media.session;
+#pragma once
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
+#include "StatsPuller.h"
+
+namespace android {
+namespace os {
+namespace statsd {
/**
- * Abstract class for mainline module services.
- *
- * @hide // TODO: Make it as a @SystemApi
+ * Reads train info from disk.
*/
-public abstract class MediaSessionProviderService extends Service {
+class TrainInfoPuller : public StatsPuller {
+ public:
+ TrainInfoPuller();
+
+ private:
+ bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
+};
- @Override
- public IBinder onBind(Intent intent) {
- // TODO: Return IMediaSessionProviderService.Stub()
- return null;
- }
-}
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index c4034ffeee22..d661ee8651be 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -82,6 +82,8 @@ const int FIELD_ID_CONFIG_STATS_METRIC_STATS = 15;
const int FIELD_ID_CONFIG_STATS_ALERT_STATS = 16;
const int FIELD_ID_CONFIG_STATS_METRIC_DIMENSION_IN_CONDITION_STATS = 17;
const int FIELD_ID_CONFIG_STATS_ANNOTATION = 18;
+const int FIELD_ID_CONFIG_STATS_ACTIVATION = 22;
+const int FIELD_ID_CONFIG_STATS_DEACTIVATION = 23;
const int FIELD_ID_CONFIG_STATS_ANNOTATION_INT64 = 1;
const int FIELD_ID_CONFIG_STATS_ANNOTATION_INT32 = 2;
@@ -206,6 +208,25 @@ void StatsdStats::noteBroadcastSent(const ConfigKey& key, int32_t timeSec) {
it->second->broadcast_sent_time_sec.push_back(timeSec);
}
+void StatsdStats::noteActiveStatusChanged(const ConfigKey& key, bool activated) {
+ noteActiveStatusChanged(key, activated, getWallClockSec());
+}
+
+void StatsdStats::noteActiveStatusChanged(const ConfigKey& key, bool activated, int32_t timeSec) {
+ lock_guard<std::mutex> lock(mLock);
+ auto it = mConfigStats.find(key);
+ if (it == mConfigStats.end()) {
+ ALOGE("Config key %s not found!", key.ToString().c_str());
+ return;
+ }
+ auto& vec = activated ? it->second->activation_time_sec
+ : it->second->deactivation_time_sec;
+ if (vec.size() == kMaxTimestampCount) {
+ vec.pop_front();
+ }
+ vec.push_back(timeSec);
+}
+
void StatsdStats::noteDataDropped(const ConfigKey& key, const size_t totalBytes) {
noteDataDropped(key, totalBytes, getWallClockSec());
}
@@ -423,6 +444,15 @@ void StatsdStats::noteEmptyData(int atomId) {
mPulledAtomStats[atomId].emptyData++;
}
+void StatsdStats::notePullerCallbackRegistrationChanged(int atomId, bool registered) {
+ lock_guard<std::mutex> lock(mLock);
+ if (registered) {
+ mPulledAtomStats[atomId].registeredCount++;
+ } else {
+ mPulledAtomStats[atomId].unregisteredCount++;
+ }
+}
+
void StatsdStats::noteHardDimensionLimitReached(int64_t metricId) {
lock_guard<std::mutex> lock(mLock);
getAtomMetricStats(metricId).hardDimensionLimitReached++;
@@ -448,6 +478,11 @@ void StatsdStats::noteBucketDropped(int64_t metricId) {
getAtomMetricStats(metricId).bucketDropped++;
}
+void StatsdStats::noteBucketUnknownCondition(int64_t metricId) {
+ lock_guard<std::mutex> lock(mLock);
+ getAtomMetricStats(metricId).bucketUnknownCondition++;
+}
+
void StatsdStats::noteConditionChangeInNextBucket(int64_t metricId) {
lock_guard<std::mutex> lock(mLock);
getAtomMetricStats(metricId).conditionChangeInNextBucket++;
@@ -467,7 +502,7 @@ void StatsdStats::noteBucketBoundaryDelayNs(int64_t metricId, int64_t timeDelayN
std::min(pullStats.minBucketBoundaryDelayNs, timeDelayNs);
}
-StatsdStats::AtomMetricStats& StatsdStats::getAtomMetricStats(int metricId) {
+StatsdStats::AtomMetricStats& StatsdStats::getAtomMetricStats(int64_t metricId) {
auto atomMetricStatsIter = mAtomMetricStats.find(metricId);
if (atomMetricStatsIter != mAtomMetricStats.end()) {
return atomMetricStatsIter->second;
@@ -492,6 +527,8 @@ void StatsdStats::resetInternalLocked() {
mLogLossStats.clear();
for (auto& config : mConfigStats) {
config.second->broadcast_sent_time_sec.clear();
+ config.second->activation_time_sec.clear();
+ config.second->deactivation_time_sec.clear();
config.second->data_drop_time_sec.clear();
config.second->data_drop_bytes.clear();
config.second->dump_report_stats.clear();
@@ -514,6 +551,8 @@ void StatsdStats::resetInternalLocked() {
pullStats.second.dataError = 0;
pullStats.second.pullTimeout = 0;
pullStats.second.pullExceedMaxDelay = 0;
+ pullStats.second.registeredCount = 0;
+ pullStats.second.unregisteredCount = 0;
}
mAtomMetricStats.clear();
}
@@ -547,6 +586,14 @@ void StatsdStats::dumpStats(int out) const {
dprintf(out, "\tbroadcast time: %d\n", broadcastTime);
}
+ for (const int& activationTime : configStats->activation_time_sec) {
+ dprintf(out, "\tactivation time: %d\n", activationTime);
+ }
+
+ for (const int& deactivationTime : configStats->deactivation_time_sec) {
+ dprintf(out, "\tdeactivation time: %d\n", deactivationTime);
+ }
+
auto dropTimePtr = configStats->data_drop_time_sec.begin();
auto dropBytesPtr = configStats->data_drop_bytes.begin();
for (int i = 0; i < (int)configStats->data_drop_time_sec.size();
@@ -575,6 +622,14 @@ void StatsdStats::dumpStats(int out) const {
(long long)broadcastTime);
}
+ for (const int& activationTime : configStats->activation_time_sec) {
+ dprintf(out, "\tactivation time: %d\n", activationTime);
+ }
+
+ for (const int& deactivationTime : configStats->deactivation_time_sec) {
+ dprintf(out, "\tdeactivation time: %d\n", deactivationTime);
+ }
+
auto dropTimePtr = configStats->data_drop_time_sec.begin();
auto dropBytesPtr = configStats->data_drop_bytes.begin();
for (int i = 0; i < (int)configStats->data_drop_time_sec.size();
@@ -625,12 +680,14 @@ void StatsdStats::dumpStats(int out) const {
" (average pull time nanos)%lld, (max pull time nanos)%lld, (average pull delay "
"nanos)%lld, "
" (max pull delay nanos)%lld, (data error)%ld\n"
- " (pull timeout)%ld, (pull exceed max delay)%ld\n",
+ " (pull timeout)%ld, (pull exceed max delay)%ld\n"
+ " (registered count) %ld, (unregistered count) %ld\n",
(int)pair.first, (long)pair.second.totalPull, (long)pair.second.totalPullFromCache,
(long)pair.second.minPullIntervalSec, (long long)pair.second.avgPullTimeNs,
(long long)pair.second.maxPullTimeNs, (long long)pair.second.avgPullDelayNs,
(long long)pair.second.maxPullDelayNs, pair.second.dataError,
- pair.second.pullTimeout, pair.second.pullExceedMaxDelay);
+ pair.second.pullTimeout, pair.second.pullExceedMaxDelay,
+ pair.second.registeredCount, pair.second.unregisteredCount);
}
if (mAnomalyAlarmRegisteredStats > 0) {
@@ -683,6 +740,16 @@ void addConfigStatsToProto(const ConfigStats& configStats, ProtoOutputStream* pr
broadcast);
}
+ for (const auto& activation : configStats.activation_time_sec) {
+ proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_ACTIVATION | FIELD_COUNT_REPEATED,
+ activation);
+ }
+
+ for (const auto& deactivation : configStats.deactivation_time_sec) {
+ proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_DEACTIVATION | FIELD_COUNT_REPEATED,
+ deactivation);
+ }
+
for (const auto& drop_time : configStats.data_drop_time_sec) {
proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_DATA_DROP_TIME | FIELD_COUNT_REPEATED,
drop_time);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 2999b649a509..e039be2b4395 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -42,6 +42,13 @@ struct ConfigStats {
bool is_valid;
std::list<int32_t> broadcast_sent_time_sec;
+
+ // Times at which this config is activated.
+ std::list<int32_t> activation_time_sec;
+
+ // Times at which this config is deactivated.
+ std::list<int32_t> deactivation_time_sec;
+
std::list<int32_t> data_drop_time_sec;
// Number of bytes dropped at corresponding time.
std::list<int64_t> data_drop_bytes;
@@ -132,6 +139,9 @@ public:
/* Min period between two checks of byte size per config key in nanoseconds. */
static const int64_t kMinByteSizeCheckPeriodNs = 60 * NS_PER_SEC;
+ /* Minimum period between two activation broadcasts in nanoseconds. */
+ static const int64_t kMinActivationBroadcastPeriodNs = 10 * NS_PER_SEC;
+
// Maximum age (30 days) that files on disk can exist in seconds.
static const int kMaxAgeSecond = 60 * 60 * 24 * 30;
@@ -146,6 +156,10 @@ public:
// Max time to do a pull.
static const int64_t kPullMaxDelayNs = 10 * NS_PER_SEC;
+
+ // Max platform atom tag number.
+ static const int32_t kMaxPlatformAtomTag = 100000;
+
/**
* Report a new config has been received and report the static stats about the config.
*
@@ -171,6 +185,13 @@ public:
void noteBroadcastSent(const ConfigKey& key);
/**
+ * Report that a config has become activated or deactivated.
+ * This can be different from whether or not a broadcast is sent if the
+ * guardrail prevented the broadcast from being sent.
+ */
+ void noteActiveStatusChanged(const ConfigKey& key, bool activate);
+
+ /**
* Report a config's metrics data has been dropped.
*/
void noteDataDropped(const ConfigKey& key, const size_t totalBytes);
@@ -340,6 +361,13 @@ public:
void noteEmptyData(int atomId);
/**
+ * Records that a puller callback for the given atomId was registered or unregistered.
+ *
+ * @param registered True if the callback was registered, false if was unregistered.
+ */
+ void notePullerCallbackRegistrationChanged(int atomId, bool registered);
+
+ /**
* Hard limit was reached in the cardinality of an atom
*/
void noteHardDimensionLimitReached(int64_t metricId);
@@ -381,6 +409,11 @@ public:
void noteBucketBoundaryDelayNs(int64_t metricId, int64_t timeDelayNs);
/**
+ * Number of buckets with unknown condition.
+ */
+ void noteBucketUnknownCondition(int64_t metricId);
+
+ /**
* Reset the historical stats. Including all stats in icebox, and the tracked stats about
* metrics, matchers, and atoms. The active configs will be kept and StatsdStats will continue
* to collect stats after reset() has been called.
@@ -416,6 +449,8 @@ public:
long statsCompanionPullFailed = 0;
long statsCompanionPullBinderTransactionFailed = 0;
long emptyData = 0;
+ long registeredCount = 0;
+ long unregisteredCount = 0;
} PulledAtomStats;
typedef struct {
@@ -428,6 +463,7 @@ public:
long bucketDropped = 0;
int64_t minBucketBoundaryDelayNs = 0;
int64_t maxBucketBoundaryDelayNs = 0;
+ long bucketUnknownCondition = 0;
} AtomMetricStats;
private:
@@ -458,7 +494,7 @@ private:
std::map<int, PulledAtomStats> mPulledAtomStats;
// Maps metric ID to its stats. The size is capped by the number of metrics.
- std::map<int, AtomMetricStats> mAtomMetricStats;
+ std::map<int64_t, AtomMetricStats> mAtomMetricStats;
struct LogLossStats {
LogLossStats(int32_t sec, int32_t count, int32_t error)
@@ -494,13 +530,15 @@ private:
void noteBroadcastSent(const ConfigKey& key, int32_t timeSec);
+ void noteActiveStatusChanged(const ConfigKey& key, bool activate, int32_t timeSec);
+
void addToIceBoxLocked(std::shared_ptr<ConfigStats>& stats);
/**
* Get a reference to AtomMetricStats for a metric. If none exists, create it. The reference
* will live as long as `this`.
*/
- StatsdStats::AtomMetricStats& getAtomMetricStats(int metricId);
+ StatsdStats::AtomMetricStats& getAtomMetricStats(int64_t metricId);
FRIEND_TEST(StatsdStatsTest, TestValidConfigAdd);
FRIEND_TEST(StatsdStatsTest, TestInvalidConfigAdd);
@@ -511,6 +549,7 @@ private:
FRIEND_TEST(StatsdStatsTest, TestAnomalyMonitor);
FRIEND_TEST(StatsdStatsTest, TestSystemServerCrash);
FRIEND_TEST(StatsdStatsTest, TestPullAtomStats);
+ FRIEND_TEST(StatsdStatsTest, TestAtomMetricsStats);
};
} // namespace statsd
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 40a4070d2974..dec36b54a1ce 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -20,6 +20,8 @@
#include "stats_log_util.h"
#include "statslog.h"
+#include <binder/IPCThreadState.h>
+
namespace android {
namespace os {
namespace statsd {
@@ -180,6 +182,25 @@ LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedT
}
}
+LogEvent::LogEvent(const string& trainName, int64_t trainVersionCode, bool requiresStaging,
+ bool rollbackEnabled, bool requiresLowLatencyMonitor, int32_t state,
+ const std::vector<uint8_t>& experimentIds, int32_t userId) {
+ mLogdTimestampNs = getWallClockNs();
+ mElapsedTimestampNs = getElapsedRealtimeNs();
+ mTagId = android::util::BINARY_PUSH_STATE_CHANGED;
+ mLogUid = android::IPCThreadState::self()->getCallingUid();
+
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)), Value(trainName)));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(trainVersionCode)));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)), Value((int)requiresStaging)));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)), Value((int)rollbackEnabled)));
+ mValues.push_back(
+ FieldValue(Field(mTagId, getSimpleField(5)), Value((int)requiresLowLatencyMonitor)));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(6)), Value(state)));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(7)), Value(experimentIds)));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(8)), Value(userId)));
+}
+
LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
const SpeakerImpedance& speakerImpedance) {
mLogdTimestampNs = wallClockTimestampNs;
@@ -340,6 +361,16 @@ LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
}
}
+LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+ const InstallTrainInfo& trainInfo) {
+ mLogdTimestampNs = wallClockTimestampNs;
+ mElapsedTimestampNs = elapsedTimestampNs;
+ mTagId = android::util::TRAIN_INFO;
+ mValues.push_back(
+ FieldValue(Field(mTagId, getSimpleField(1)), Value(trainInfo.trainVersionCode)));
+ mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(trainInfo.experimentIds)));
+}
+
LogEvent::LogEvent(int32_t tagId, int64_t timestampNs) : LogEvent(tagId, timestampNs, 0) {}
LogEvent::LogEvent(int32_t tagId, int64_t timestampNs, int32_t uid) {
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 784376a1580c..111a619760df 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -55,6 +55,11 @@ struct AttributionNodeInternal {
int32_t mUid;
std::string mTag;
};
+
+struct InstallTrainInfo {
+ int64_t trainVersionCode;
+ std::vector<uint8_t> experimentIds;
+};
/**
* Wrapper for the log_msg structure.
*/
@@ -97,6 +102,11 @@ public:
const std::map<int32_t, std::string>& string_map,
const std::map<int32_t, float>& float_map);
+ // Constructs a BinaryPushStateChanged LogEvent from API call.
+ explicit LogEvent(const std::string& trainName, int64_t trainVersionCode, bool requiresStaging,
+ bool rollbackEnabled, bool requiresLowLatencyMonitor, int32_t state,
+ const std::vector<uint8_t>& experimentIds, int32_t userId);
+
explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
const SpeakerImpedance& speakerImpedance);
@@ -127,6 +137,9 @@ public:
explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
const VendorAtom& vendorAtom);
+ explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+ const InstallTrainInfo& installTrainInfo);
+
~LogEvent();
/**
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 350745b2c326..5707de544648 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -250,7 +250,7 @@ void CountMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
void CountMetricProducer::onConditionChangedLocked(const bool conditionMet,
const int64_t eventTime) {
VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
- mCondition = conditionMet;
+ mCondition = conditionMet ? ConditionState::kTrue : ConditionState::kFalse;
}
bool CountMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 6c1c47bbc093..da6b97cc4e59 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -433,7 +433,7 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondit
void DurationMetricProducer::onConditionChangedLocked(const bool conditionMet,
const int64_t eventTime) {
VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
- mCondition = conditionMet;
+ mCondition = conditionMet ? ConditionState::kTrue : ConditionState::kFalse;
flushIfNeededLocked(eventTime);
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
for (auto& pair : whatIt.second) {
@@ -767,12 +767,13 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
!mSameConditionDimensionsInTracker,
!mHasLinksToAllConditionDimensionsInTracker,
&dimensionKeysInCondition);
- condition = (conditionState == ConditionState::kTrue);
+ condition = conditionState == ConditionState::kTrue;
if (mDimensionsInCondition.empty() && condition) {
dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
}
} else {
- condition = mCondition;
+ // TODO: The unknown condition state is not handled here, we should fix it.
+ condition = mCondition == ConditionState::kTrue;
if (condition) {
dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
}
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 1b830a3f69f5..ec561b527025 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -137,6 +137,7 @@ private:
FRIEND_TEST(DurationMetricTrackerTest, TestNoCondition);
FRIEND_TEST(DurationMetricTrackerTest, TestNonSlicedCondition);
+ FRIEND_TEST(DurationMetricTrackerTest, TestNonSlicedConditionUnknownState);
FRIEND_TEST(DurationMetricTrackerTest, TestSumDurationWithUpgrade);
FRIEND_TEST(DurationMetricTrackerTest, TestSumDurationWithUpgradeInFollowingBucket);
FRIEND_TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgrade);
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 7e695a69988f..3b4af6533e34 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -132,7 +132,7 @@ void EventMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
void EventMetricProducer::onConditionChangedLocked(const bool conditionMet,
const int64_t eventTime) {
VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
- mCondition = conditionMet;
+ mCondition = conditionMet ? ConditionState::kTrue : ConditionState::kFalse;
}
void EventMetricProducer::onMatchedLogEventInternalLocked(
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index d56a355f15d6..837d532f7e09 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -320,15 +320,15 @@ void GaugeMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
// When the metric wants to do random sampling and there is already one gauge atom for the
// current bucket, do not do it again.
case GaugeMetric::RANDOM_ONE_SAMPLE: {
- triggerPuller = mCondition && mCurrentSlicedBucket->empty();
+ triggerPuller = mCondition == ConditionState::kTrue && mCurrentSlicedBucket->empty();
break;
}
case GaugeMetric::CONDITION_CHANGE_TO_TRUE: {
- triggerPuller = mCondition;
+ triggerPuller = mCondition == ConditionState::kTrue;
break;
}
case GaugeMetric::FIRST_N_SAMPLES: {
- triggerPuller = mCondition;
+ triggerPuller = mCondition == ConditionState::kTrue;
break;
}
default:
@@ -364,7 +364,7 @@ void GaugeMetricProducer::onConditionChangedLocked(const bool conditionMet,
const int64_t eventTimeNs) {
VLOG("GaugeMetric %lld onConditionChanged", (long long)mMetricId);
flushIfNeededLocked(eventTimeNs);
- mCondition = conditionMet;
+ mCondition = conditionMet ? ConditionState::kTrue : ConditionState::kFalse;
if (mIsPulled && mTriggerAtomId == -1) {
pullAndMatchEventsLocked(eventTimeNs);
} // else: Push mode. No need to proactively pull the gauge data.
@@ -377,7 +377,7 @@ void GaugeMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition
flushIfNeededLocked(eventTimeNs);
// If the condition is sliced, mCondition is true if any of the dimensions is true. And we will
// pull for every dimension.
- mCondition = overallCondition;
+ mCondition = overallCondition ? ConditionState::kTrue : ConditionState::kFalse;
if (mIsPulled && mTriggerAtomId == -1) {
pullAndMatchEventsLocked(eventTimeNs);
} // else: Push mode. No need to proactively pull the gauge data.
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index b362e37cd194..4cf5333947d3 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -45,7 +45,8 @@ void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const Lo
&dimensionKeysInCondition);
condition = (conditionState == ConditionState::kTrue);
} else {
- condition = mCondition;
+ // TODO: The unknown condition state is not handled here, we should fix it.
+ condition = mCondition == ConditionState::kTrue;
}
if (mDimensionsInCondition.empty() && condition) {
@@ -94,7 +95,7 @@ void MetricProducer::flushIfExpire(int64_t elapsedTimestampNs) {
void MetricProducer::addActivation(int activationTrackerIndex, int64_t ttl_seconds) {
std::lock_guard<std::mutex> lock(mMutex);
// When a metric producer does not depend on any activation, its mIsActive is true.
- // Therefor, if this is the 1st activation, mIsActive will turn to false. Otherwise it does not
+ // Therefore, if this is the 1st activation, mIsActive will turn to false. Otherwise it does not
// change.
if (mEventActivationMap.empty()) {
mIsActive = false;
@@ -107,6 +108,11 @@ void MetricProducer::activateLocked(int activationTrackerIndex, int64_t elapsedT
if (it == mEventActivationMap.end()) {
return;
}
+ if (mActivationType == MetricActivation::ACTIVATE_ON_BOOT &&
+ it->second.state == ActivationState::kNotActive) {
+ it->second.state = ActivationState::kActiveOnBoot;
+ return;
+ }
it->second.activation_ns = elapsedTimestampNs;
it->second.state = ActivationState::kActive;
mIsActive = true;
@@ -116,12 +122,19 @@ void MetricProducer::setActiveLocked(int64_t currentTimeNs, int64_t remainingTtl
if (mEventActivationMap.size() == 0) {
return;
}
- auto& activation = mEventActivationMap.begin()->second;
- activation.activation_ns = currentTimeNs + remainingTtlNs - activation.ttl_ns;
- activation.state = kActive;
- mIsActive = true;
- VLOG("setting new activation time to %lld, %lld, %lld", (long long)activation.activation_ns,
- (long long)currentTimeNs, (long long)remainingTtlNs);
+ for (auto& pair : mEventActivationMap) {
+ auto& activation = pair.second;
+ if (activation.ttl_ns >= remainingTtlNs) {
+ activation.activation_ns = currentTimeNs + remainingTtlNs - activation.ttl_ns;
+ activation.state = kActive;
+ mIsActive = true;
+ VLOG("setting new activation time to %lld, %lld, %lld",
+ (long long)activation.activation_ns, (long long)currentTimeNs,
+ (long long)remainingTtlNs);
+ return;
+ }
+ }
+ ALOGE("Required ttl is longer than all possible activations.");
}
int64_t MetricProducer::getRemainingTtlNsLocked(int64_t currentTimeNs) const {
@@ -135,6 +148,19 @@ int64_t MetricProducer::getRemainingTtlNsLocked(int64_t currentTimeNs) const {
return maxTtl;
}
+void MetricProducer::prepActiveForBootIfNecessaryLocked(int64_t currentTimeNs) {
+ if (mActivationType != MetricActivation::ACTIVATE_ON_BOOT) {
+ return;
+ }
+ for (auto& activation : mEventActivationMap) {
+ if (activation.second.state == kActiveOnBoot) {
+ activation.second.state = kActive;
+ activation.second.activation_ns = currentTimeNs;
+ mIsActive = true;
+ }
+ }
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index ca37bbb73b45..8ab3b0680276 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -37,12 +37,13 @@ namespace statsd {
// If the metric has no activation requirement, it will be active once the metric producer is
// created.
// If the metric needs to be activated by atoms, the metric producer will start
-// with kNotActive state, turn to kActive when the activation event arrives, become kNotActive
-// when it reaches the duration limit (timebomb). If the activation event arrives again before
-// or after it expires, the event producer will be re-activated and ttl will be reset.
+// with kNotActive state, turn to kActive or kActiveOnBoot when the activation event arrives, become
+// kNotActive when it reaches the duration limit (timebomb). If the activation event arrives again
+// before or after it expires, the event producer will be re-activated and ttl will be reset.
enum ActivationState {
kNotActive = 0,
kActive = 1,
+ kActiveOnBoot = 2,
};
// A MetricProducer is responsible for compute one single metrics, creating stats log report, and
@@ -58,7 +59,7 @@ public:
mTimeBaseNs(timeBaseNs),
mCurrentBucketStartTimeNs(timeBaseNs),
mCurrentBucketNum(0),
- mCondition(conditionIndex >= 0 ? false : true),
+ mCondition(conditionIndex >= 0 ? ConditionState::kUnknown : ConditionState::kTrue),
mConditionSliced(false),
mWizard(wizard),
mConditionTrackerIndex(conditionIndex),
@@ -218,8 +219,17 @@ public:
return isActiveLocked();
}
+ void prepActiveForBootIfNecessary(int64_t currentTimeNs) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ prepActiveForBootIfNecessaryLocked(currentTimeNs);
+ }
+
void addActivation(int activationTrackerIndex, int64_t ttl_seconds);
+ inline void setActivationType(const MetricActivation::ActivationType& activationType) {
+ mActivationType = activationType;
+ }
+
void flushIfExpire(int64_t elapsedTimestampNs);
protected:
@@ -243,6 +253,8 @@ protected:
return mIsActive;
}
+ void prepActiveForBootIfNecessaryLocked(int64_t currentTimeNs);
+
int64_t getRemainingTtlNsLocked(int64_t currentTimeNs) const;
void setActiveLocked(int64_t currentTimeNs, int64_t remainingTtlNs);
@@ -303,7 +315,7 @@ protected:
int64_t mBucketSizeNs;
- bool mCondition;
+ ConditionState mCondition;
bool mConditionSliced;
@@ -367,9 +379,12 @@ protected:
bool mIsActive;
+ MetricActivation::ActivationType mActivationType;
+
FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
+ FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 6ed6ab500597..4851a8d40baa 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -118,6 +118,16 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
ALOGE("This config has too many alerts! Reject!");
mConfigValid = false;
}
+
+ mIsAlwaysActive = (mMetricIndexesWithActivation.size() != mAllMetricProducers.size()) ||
+ (mAllMetricProducers.size() == 0);
+ bool isActive = mIsAlwaysActive;
+ for (int metric : mMetricIndexesWithActivation) {
+ isActive |= mAllMetricProducers[metric]->isActive();
+ }
+ mIsActive = isActive;
+ VLOG("mIsActive is initialized to %d", mIsActive)
+
// no matter whether this config is valid, log it in the stats.
StatsdStats::getInstance().noteConfigReceived(
key, mAllMetricProducers.size(), mAllConditionTrackers.size(), mAllAtomMatchers.size(),
@@ -332,12 +342,14 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
int tagId = event.GetTagId();
int64_t eventTimeNs = event.GetElapsedTimestampNs();
- bool isActive = false;
+ bool isActive = mIsAlwaysActive;
for (int metric : mMetricIndexesWithActivation) {
mAllMetricProducers[metric]->flushIfExpire(eventTimeNs);
isActive |= mAllMetricProducers[metric]->isActive();
}
+ mIsActive = isActive;
+
if (mTagIds.find(tagId) == mTagIds.end()) {
// not interesting...
return;
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index fdc28ea7f219..eab1f762b390 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -128,11 +128,13 @@ public:
// Does not change the state.
virtual size_t byteSize();
+ // Returns whether or not this config is active.
+ // The config is active if any metric in the config is active.
inline bool isActive() const {
return mIsActive;
}
- inline void getActiveMetrics(std::vector<const MetricProducer*>& metrics) const {
+ inline void getActiveMetrics(std::vector<MetricProducer*>& metrics) const {
for (const auto& metric : mAllMetricProducers) {
if (metric->isActive()) {
metrics.push_back(metric.get());
@@ -140,6 +142,12 @@ public:
}
}
+ inline void prepForShutDown(int64_t currentTimeNs) {
+ for (const auto& metric : mAllMetricProducers) {
+ metric->prepActiveForBootIfNecessary(currentTimeNs);
+ }
+ }
+
void setActiveMetrics(ActiveConfig config, int64_t currentTimeNs);
private:
@@ -235,9 +243,12 @@ private:
// The metrics that don't need to be uploaded or even reported.
std::set<int64_t> mNoReportMetricIds;
- // Any metric active means the config is active.
+ // The config is active if any metric in the config is active.
bool mIsActive;
+ // The config is always active if any metric in the config does not have an activation signal.
+ bool mIsAlwaysActive;
+
FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensions);
FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks);
FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid);
@@ -271,6 +282,7 @@ private:
FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
+ FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index ac6c27adceaa..bc7c8727284f 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -154,7 +154,7 @@ ValueMetricProducer::ValueMetricProducer(
// Adjust start for partial bucket
mCurrentBucketStartTimeNs = startTimeNs;
// Kicks off the puller immediately if condition is true and diff based.
- if (mIsPulled && mCondition && mUseDiff) {
+ if (mIsPulled && mCondition == ConditionState::kTrue && mUseDiff) {
pullAndMatchEventsLocked(startTimeNs);
}
VLOG("value metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
@@ -341,17 +341,21 @@ void ValueMetricProducer::onConditionChangedLocked(const bool condition,
flushIfNeededLocked(eventTimeNs);
// Pull on condition changes.
- if (mIsPulled && (mCondition != condition)) {
+ bool conditionChanged = mCondition != condition;
+ bool unknownToFalse = mCondition == ConditionState::kUnknown
+ && condition == ConditionState::kFalse;
+ // We do not need to pull when we go from unknown to false.
+ if (mIsPulled && conditionChanged && !unknownToFalse) {
pullAndMatchEventsLocked(eventTimeNs);
}
// when condition change from true to false, clear diff base but don't
// reset other counters as we may accumulate more value in the bucket.
- if (mUseDiff && mCondition && !condition) {
+ if (mUseDiff && mCondition == ConditionState::kTrue && condition == ConditionState::kFalse) {
resetBase();
}
- mCondition = condition;
+ mCondition = condition ? ConditionState::kTrue : ConditionState::kFalse;
}
void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
@@ -372,7 +376,7 @@ int64_t ValueMetricProducer::calcPreviousBucketEndTime(const int64_t currentTime
void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData,
bool pullSuccess, int64_t originalPullTimeNs) {
std::lock_guard<std::mutex> lock(mMutex);
- if (mCondition) {
+ if (mCondition == ConditionState::kTrue) {
if (!pullSuccess) {
// If the pull failed, we won't be able to compute a diff.
invalidateCurrentBucket();
@@ -450,6 +454,17 @@ void ValueMetricProducer::accumulateEvents(const std::vector<std::shared_ptr<Log
}
mMatchedMetricDimensionKeys.clear();
mHasGlobalBase = true;
+
+ // If we reach the guardrail, we might have dropped some data which means the bucket is
+ // incomplete.
+ //
+ // The base also needs to be reset. If we do not have the full data, we might
+ // incorrectly compute the diff when mUseZeroDefaultBase is true since an existing key
+ // might be missing from mCurrentSlicedBucket.
+ if (hasReachedGuardRailLimit()) {
+ invalidateCurrentBucket();
+ mCurrentSlicedBucket.clear();
+ }
}
void ValueMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
@@ -471,6 +486,10 @@ void ValueMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
}
}
+bool ValueMetricProducer::hasReachedGuardRailLimit() const {
+ return mCurrentSlicedBucket.size() >= mDimensionHardLimit;
+}
+
bool ValueMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
// ===========GuardRail==============
// 1. Report the tuple count if the tuple count > soft limit
@@ -481,7 +500,7 @@ bool ValueMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
size_t newTupleCount = mCurrentSlicedBucket.size() + 1;
StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
- if (newTupleCount > mDimensionHardLimit) {
+ if (hasReachedGuardRailLimit()) {
ALOGE("ValueMetric %lld dropping data for dimension key %s", (long long)mMetricId,
newKey.toString().c_str());
StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
@@ -710,6 +729,10 @@ void ValueMetricProducer::flushIfNeededLocked(const int64_t& eventTimeNs) {
}
void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs) {
+ if (mCondition == ConditionState::kUnknown) {
+ StatsdStats::getInstance().noteBucketUnknownCondition(mMetricId);
+ }
+
VLOG("finalizing bucket for %ld, dumping %d slices", (long)mCurrentBucketStartTimeNs,
(int)mCurrentSlicedBucket.size());
int64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index d1c2315b28be..f26ad85acf05 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -158,6 +158,7 @@ private:
// Util function to check whether the specified dimension hits the guardrail.
bool hitGuardRailLocked(const MetricDimensionKey& newKey);
+ bool hasReachedGuardRailLimit() const;
bool hitFullBucketGuardRailLocked(const MetricDimensionKey& newKey);
@@ -244,6 +245,7 @@ private:
FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfBucket);
FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate);
FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenOneConditionFailed);
+ FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenGuardRailHit);
FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed);
FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenLastPullFailed);
FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded);
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 180a1ae07523..463b5a097585 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -725,6 +725,8 @@ bool initMetricActivations(const ConfigKey& key, const StatsdConfig& config,
ALOGE("Invalid metric tracker index.");
return false;
}
+ allMetricProducers[metricTrackerIndex]->setActivationType(
+ metric_activation.activation_type());
metricsWithActivation.push_back(metricTrackerIndex);
for (int j = 0; j < metric_activation.event_activation_size(); ++j) {
const EventActivation& activation = metric_activation.event_activation(j);
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 6a07a3f169e0..09b8fed60dcc 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -367,6 +367,8 @@ message StatsdStatsReport {
optional int32 field_int32 = 2;
}
repeated Annotation annotation = 18;
+ repeated int32 activation_time_sec = 22;
+ repeated int32 deactivation_time_sec = 23;
}
repeated ConfigStats config_stats = 3;
@@ -407,6 +409,8 @@ message StatsdStatsReport {
optional int64 stats_companion_pull_failed = 13;
optional int64 stats_companion_pull_binder_transaction_failed = 14;
optional int64 empty_data = 15;
+ optional int64 registered_count = 16;
+ optional int64 unregistered_count = 17;
}
repeated PulledAtomStats pulled_atom_stats = 10;
@@ -421,6 +425,7 @@ message StatsdStatsReport {
optional int64 bucket_dropped = 8;
optional int64 min_bucket_boundary_delay_ns = 9;
optional int64 max_bucket_boundary_delay_ns = 10;
+ optional int64 bucket_unknown_condition = 11;
}
repeated AtomMetricStats atom_metric_stats = 17;
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index aa8cfc508861..ca645e186614 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -70,6 +70,8 @@ const int FIELD_ID_PULL_FAILED = 12;
const int FIELD_ID_STATS_COMPANION_FAILED = 13;
const int FIELD_ID_STATS_COMPANION_BINDER_TRANSACTION_FAILED = 14;
const int FIELD_ID_EMPTY_DATA = 15;
+const int FIELD_ID_PULL_REGISTERED_COUNT = 16;
+const int FIELD_ID_PULL_UNREGISTERED_COUNT = 17;
// for AtomMetricStats proto
const int FIELD_ID_ATOM_METRIC_STATS = 17;
const int FIELD_ID_METRIC_ID = 1;
@@ -82,6 +84,7 @@ const int FIELD_ID_INVALIDATED_BUCKET = 7;
const int FIELD_ID_BUCKET_DROPPED = 8;
const int FIELD_ID_MIN_BUCKET_BOUNDARY_DELAY_NS = 9;
const int FIELD_ID_MAX_BUCKET_BOUNDARY_DELAY_NS = 10;
+const int FIELD_ID_BUCKET_UNKNOWN_CONDITION = 11;
namespace {
@@ -480,14 +483,18 @@ void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>
(long long)pair.second.statsCompanionPullBinderTransactionFailed);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_EMPTY_DATA,
(long long)pair.second.emptyData);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_REGISTERED_COUNT,
+ (long long) pair.second.registeredCount);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_UNREGISTERED_COUNT,
+ (long long) pair.second.unregisteredCount);
protoOutput->end(token);
}
-void writeAtomMetricStatsToStream(const std::pair<int, StatsdStats::AtomMetricStats> &pair,
+void writeAtomMetricStatsToStream(const std::pair<int64_t, StatsdStats::AtomMetricStats> &pair,
util::ProtoOutputStream *protoOutput) {
uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOM_METRIC_STATS |
FIELD_COUNT_REPEATED);
- protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_ID, (int32_t)pair.first);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_ID, (long long)pair.first);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_HARD_DIMENSION_LIMIT_REACHED,
(long long)pair.second.hardDimensionLimitReached);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_LATE_LOG_EVENT_SKIPPED,
@@ -506,6 +513,8 @@ void writeAtomMetricStatsToStream(const std::pair<int, StatsdStats::AtomMetricSt
(long long)pair.second.minBucketBoundaryDelayNs);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MAX_BUCKET_BOUNDARY_DELAY_NS,
(long long)pair.second.maxBucketBoundaryDelayNs);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_UNKNOWN_CONDITION,
+ (long long)pair.second.bucketUnknownCondition);
protoOutput->end(token);
}
diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h
index dcea0e653e22..59d4865f8977 100644
--- a/cmds/statsd/src/stats_log_util.h
+++ b/cmds/statsd/src/stats_log_util.h
@@ -74,7 +74,7 @@ void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>
util::ProtoOutputStream* protoOutput);
// Helper function to write AtomMetricStats to ProtoOutputStream
-void writeAtomMetricStatsToStream(const std::pair<int, StatsdStats::AtomMetricStats> &pair,
+void writeAtomMetricStatsToStream(const std::pair<int64_t, StatsdStats::AtomMetricStats> &pair,
util::ProtoOutputStream *protoOutput);
template<class T>
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 9d3a66902804..5c6d548ad13a 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -379,6 +379,13 @@ message EventActivation {
message MetricActivation {
optional int64 metric_id = 1;
+ enum ActivationType {
+ UNKNOWN = 0;
+ ACTIVATE_IMMEDIATELY = 1;
+ ACTIVATE_ON_BOOT = 2;
+ }
+ optional ActivationType activation_type = 3;
+
repeated EventActivation event_activation = 2;
}
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 90f641a34b85..165e57c73743 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -38,10 +38,13 @@ using std::map;
#define STATS_DATA_DIR "/data/misc/stats-data"
#define STATS_SERVICE_DIR "/data/misc/stats-service"
+#define TRAIN_INFO_DIR "/data/misc/train-info"
// for ConfigMetricsReportList
const int FIELD_ID_REPORTS = 2;
+std::mutex StorageManager::sTrainInfoMutex;
+
using android::base::StringPrintf;
using std::unique_ptr;
@@ -92,6 +95,71 @@ void StorageManager::writeFile(const char* file, const void* buffer, int numByte
close(fd);
}
+bool StorageManager::writeTrainInfo(int64_t trainVersionCode,
+ const std::vector<uint8_t>& experimentIds) {
+ std::lock_guard<std::mutex> lock(sTrainInfoMutex);
+
+ deleteAllFiles(TRAIN_INFO_DIR);
+
+ string file_name = StringPrintf("%s/%lld", TRAIN_INFO_DIR, (long long)trainVersionCode);
+
+ int fd = open(file_name.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
+ if (fd == -1) {
+ VLOG("Attempt to access %s but failed", file_name.c_str());
+ return false;
+ }
+
+ size_t result = write(fd, experimentIds.data(), experimentIds.size());
+ if (result == experimentIds.size()) {
+ VLOG("Successfully wrote %s", file_name.c_str());
+ } else {
+ VLOG("Failed to write %s", file_name.c_str());
+ return false;
+ }
+
+ result = fchown(fd, AID_STATSD, AID_STATSD);
+ if (result) {
+ VLOG("Failed to chown %s to statsd", file_name.c_str());
+ return false;
+ }
+
+ close(fd);
+ return true;
+}
+
+bool StorageManager::readTrainInfo(InstallTrainInfo& trainInfo) {
+ std::lock_guard<std::mutex> lock(sTrainInfoMutex);
+
+ unique_ptr<DIR, decltype(&closedir)> dir(opendir(TRAIN_INFO_DIR), closedir);
+
+ if (dir == NULL) {
+ VLOG("Directory does not exist: %s", TRAIN_INFO_DIR);
+ return false;
+ }
+
+ dirent* de;
+ while ((de = readdir(dir.get()))) {
+ char* name = de->d_name;
+ if (name[0] == '.') {
+ continue;
+ }
+ trainInfo.trainVersionCode = StrToInt64(name);
+ string fullPath = StringPrintf("%s/%s", TRAIN_INFO_DIR, name);
+ int fd = open(fullPath.c_str(), O_RDONLY | O_CLOEXEC);
+ if (fd != -1) {
+ string str;
+ if (android::base::ReadFdToString(fd, &str)) {
+ close(fd);
+ std::copy(str.begin(), str.end(), std::back_inserter(trainInfo.experimentIds));
+ VLOG("Read train info file successful: %s", fullPath.c_str());
+ return true;
+ }
+ }
+ close(fd);
+ }
+ return false;
+}
+
void StorageManager::deleteFile(const char* file) {
if (remove(file) != 0) {
VLOG("Attempt to delete %s but is not found", file);
diff --git a/cmds/statsd/src/storage/StorageManager.h b/cmds/statsd/src/storage/StorageManager.h
index dcf3bb607380..d6df8674e59b 100644
--- a/cmds/statsd/src/storage/StorageManager.h
+++ b/cmds/statsd/src/storage/StorageManager.h
@@ -29,6 +29,11 @@ namespace statsd {
using android::util::ProtoOutputStream;
+struct TrainInfo {
+ int64_t trainVersionCode;
+ std::vector<uint8_t> experimentIds;
+};
+
class StorageManager : public virtual RefBase {
public:
/**
@@ -37,6 +42,16 @@ public:
static void writeFile(const char* file, const void* buffer, int numBytes);
/**
+ * Writes train info.
+ */
+ static bool writeTrainInfo(int64_t trainVersionCode, const std::vector<uint8_t>& experimentIds);
+
+ /**
+ * Reads train info.
+ */
+ static bool readTrainInfo(InstallTrainInfo& trainInfo);
+
+ /**
* Reads the file content to the buffer.
*/
static bool readFileToString(const char* file, string* content);
@@ -109,6 +124,8 @@ private:
* Prints disk usage statistics about a directory related to statsd.
*/
static void printDirStats(int out, const char* path);
+
+ static std::mutex sTrainInfoMutex;
};
} // namespace statsd
diff --git a/cmds/statsd/statsd.rc b/cmds/statsd/statsd.rc
index e0cbd5d25716..a98ecd586b42 100644
--- a/cmds/statsd/statsd.rc
+++ b/cmds/statsd/statsd.rc
@@ -27,3 +27,4 @@ on post-fs-data
mkdir /data/misc/stats-data/ 0770 statsd system
mkdir /data/misc/stats-service/ 0770 statsd system
mkdir /data/misc/stats-active-metric/ 0770 statsd system
+ mkdir /data/misc/train-info/ 0770 statsd system
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index 64008b50b013..4579ca6008ef 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -65,7 +65,8 @@ TEST(StatsLogProcessorTest, TestRateLimitByteSize) {
sp<AlarmMonitor> periodicAlarmMonitor;
// Construct the processor with a dummy sendBroadcast function that does nothing.
StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, 0,
- [](const ConfigKey& key) { return true; });
+ [](const ConfigKey& key) { return true; },
+ [](const int&, const vector<int64_t>&) {return true;});
MockMetricsManager mockMetricsManager;
@@ -88,7 +89,8 @@ TEST(StatsLogProcessorTest, TestRateLimitBroadcast) {
[&broadcastCount](const ConfigKey& key) {
broadcastCount++;
return true;
- });
+ },
+ [](const int&, const vector<int64_t>&) {return true;});
MockMetricsManager mockMetricsManager;
@@ -118,7 +120,8 @@ TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge) {
[&broadcastCount](const ConfigKey& key) {
broadcastCount++;
return true;
- });
+ },
+ [](const int&, const vector<int64_t>&) {return true;});
MockMetricsManager mockMetricsManager;
@@ -162,7 +165,8 @@ TEST(StatsLogProcessorTest, TestUidMapHasSnapshot) {
[&broadcastCount](const ConfigKey& key) {
broadcastCount++;
return true;
- });
+ },
+ [](const int&, const vector<int64_t>&) {return true;});
ConfigKey key(3, 4);
StatsdConfig config = MakeConfig(true);
p.OnConfigUpdated(0, key, config);
@@ -192,7 +196,8 @@ TEST(StatsLogProcessorTest, TestEmptyConfigHasNoUidMap) {
[&broadcastCount](const ConfigKey& key) {
broadcastCount++;
return true;
- });
+ },
+ [](const int&, const vector<int64_t>&) {return true;});
ConfigKey key(3, 4);
StatsdConfig config = MakeConfig(false);
p.OnConfigUpdated(0, key, config);
@@ -218,7 +223,8 @@ TEST(StatsLogProcessorTest, TestReportIncludesSubConfig) {
[&broadcastCount](const ConfigKey& key) {
broadcastCount++;
return true;
- });
+ },
+ [](const int&, const vector<int64_t>&) {return true;});
ConfigKey key(3, 4);
StatsdConfig config;
auto annotation = config.add_annotation();
@@ -291,7 +297,8 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
// Setup a simple config, no activation
StatsdConfig config1;
- config1.set_id(12341);
+ int64_t cfgId1 = 12341;
+ config1.set_id(cfgId1);
config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
*config1.add_atom_matcher() = wakelockAcquireMatcher;
@@ -308,14 +315,12 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
countMetric2->set_what(wakelockAcquireMatcher.id());
countMetric2->set_bucket(FIVE_MINUTES);
- ConfigKey cfgKey1(uid, 12341);
- long timeBase1 = 1;
- sp<StatsLogProcessor> processor =
- CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
+ ConfigKey cfgKey1(uid, cfgId1);
// Add another config, with two metrics, one with activation
StatsdConfig config2;
- config2.set_id(12342);
+ int64_t cfgId2 = 12342;
+ config2.set_id(cfgId2);
config2.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
*config2.add_atom_matcher() = wakelockAcquireMatcher;
@@ -338,11 +343,12 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
metric3ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
metric3ActivationTrigger->set_ttl_seconds(100);
- ConfigKey cfgKey2(uid, 12342);
+ ConfigKey cfgKey2(uid, cfgId2);
// Add another config, with two metrics, both with activations
StatsdConfig config3;
- config3.set_id(12342);
+ int64_t cfgId3 = 12343;
+ config3.set_id(cfgId3);
config3.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
*config3.add_atom_matcher() = wakelockAcquireMatcher;
@@ -370,14 +376,37 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
metric6ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
metric6ActivationTrigger->set_ttl_seconds(200);
- ConfigKey cfgKey3(uid, 12343);
+ ConfigKey cfgKey3(uid, cfgId3);
- processor->OnConfigUpdated(2, cfgKey2, config2);
- processor->OnConfigUpdated(3, cfgKey3, config3);
+ sp<UidMap> m = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
+ vector<int64_t> activeConfigsBroadcast;
- EXPECT_EQ(3, processor->mMetricsManagers.size());
- auto it = processor->mMetricsManagers.find(cfgKey1);
- EXPECT_TRUE(it != processor->mMetricsManagers.end());
+ long timeBase1 = 1;
+ int broadcastCount = 0;
+ StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
+ timeBase1, [](const ConfigKey& key) { return true; },
+ [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+ const vector<int64_t>& activeConfigs) {
+ broadcastCount++;
+ EXPECT_EQ(broadcastUid, uid);
+ activeConfigsBroadcast.clear();
+ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
+ activeConfigs.begin(), activeConfigs.end());
+ return true;
+ });
+
+ processor.OnConfigUpdated(1, cfgKey1, config1);
+ processor.OnConfigUpdated(2, cfgKey2, config2);
+ processor.OnConfigUpdated(3, cfgKey3, config3);
+
+ EXPECT_EQ(3, processor.mMetricsManagers.size());
+
+ // Expect the first config and both metrics in it to be active.
+ auto it = processor.mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor.mMetricsManagers.end());
auto& metricsManager1 = it->second;
EXPECT_TRUE(metricsManager1->isActive());
@@ -401,8 +430,9 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
auto& metricProducer2 = *metricIt;
EXPECT_TRUE(metricProducer2->isActive());
- it = processor->mMetricsManagers.find(cfgKey2);
- EXPECT_TRUE(it != processor->mMetricsManagers.end());
+ // Expect config 2 to be active. Metric 3 shouldn't be active, metric 4 should be active.
+ it = processor.mMetricsManagers.find(cfgKey2);
+ EXPECT_TRUE(it != processor.mMetricsManagers.end());
auto& metricsManager2 = it->second;
EXPECT_TRUE(metricsManager2->isActive());
@@ -426,8 +456,9 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
auto& metricProducer4 = *metricIt;
EXPECT_TRUE(metricProducer4->isActive());
- it = processor->mMetricsManagers.find(cfgKey3);
- EXPECT_TRUE(it != processor->mMetricsManagers.end());
+ // Expect the third config and both metrics in it to be inactive.
+ it = processor.mMetricsManagers.find(cfgKey3);
+ EXPECT_TRUE(it != processor.mMetricsManagers.end());
auto& metricsManager3 = it->second;
EXPECT_FALSE(metricsManager3->isActive());
@@ -451,10 +482,30 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
auto& metricProducer6 = *metricIt;
EXPECT_FALSE(metricProducer6->isActive());
+ // No broadcast for active configs should have happened yet.
+ EXPECT_EQ(broadcastCount, 0);
+
+ // Activate all 3 metrics that were not active.
std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1);
- processor->OnLogEvent(event.get());
+ processor.OnLogEvent(event.get());
+ // Assert that all 3 configs are active.
+ EXPECT_TRUE(metricsManager1->isActive());
+ EXPECT_TRUE(metricsManager2->isActive());
+ EXPECT_TRUE(metricsManager3->isActive());
+
+ // A broadcast should have happened, and all 3 configs should be active in the broadcast.
+ EXPECT_EQ(broadcastCount, 1);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 3);
+ EXPECT_TRUE(std::find(activeConfigsBroadcast.begin(), activeConfigsBroadcast.end(), cfgId1)
+ != activeConfigsBroadcast.end());
+ EXPECT_TRUE(std::find(activeConfigsBroadcast.begin(), activeConfigsBroadcast.end(), cfgId2)
+ != activeConfigsBroadcast.end());
+ EXPECT_TRUE(std::find(activeConfigsBroadcast.begin(), activeConfigsBroadcast.end(), cfgId3)
+ != activeConfigsBroadcast.end());
+
+ // When we shut down, metrics 3 & 5 have 100ns remaining, metric 6 has 100s + 100ns.
int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
EXPECT_TRUE(metricProducer3->isActive());
int64_t ttl3 = metricProducer3->getRemainingTtlNs(shutDownTime);
@@ -466,8 +517,9 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
int64_t ttl6 = metricProducer6->getRemainingTtlNs(shutDownTime);
EXPECT_EQ(100 + 100 * NS_PER_SEC, ttl6);
- processor->WriteMetricsActivationToDisk(timeBase1 + 100 * NS_PER_SEC);
+ processor.WriteMetricsActivationToDisk(shutDownTime);
+ // Create a second StatsLogProcessor and push the same 3 configs.
long timeBase2 = 1000;
sp<StatsLogProcessor> processor2 =
CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
@@ -475,6 +527,8 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
processor2->OnConfigUpdated(timeBase2, cfgKey3, config3);
EXPECT_EQ(3, processor2->mMetricsManagers.size());
+
+ // First config and both metrics are active.
it = processor2->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor2->mMetricsManagers.end());
auto& metricsManager1001 = it->second;
@@ -500,6 +554,7 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
auto& metricProducer1002 = *metricIt;
EXPECT_TRUE(metricProducer1002->isActive());
+ // Second config is active. Metric 3 is inactive, metric 4 is active.
it = processor2->mMetricsManagers.find(cfgKey2);
EXPECT_TRUE(it != processor2->mMetricsManagers.end());
auto& metricsManager1002 = it->second;
@@ -525,6 +580,7 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
auto& metricProducer1004 = *metricIt;
EXPECT_TRUE(metricProducer1004->isActive());
+ // Config 3 is inactive. both metrics are inactive.
it = processor2->mMetricsManagers.find(cfgKey3);
EXPECT_TRUE(it != processor2->mMetricsManagers.end());
auto& metricsManager1003 = it->second;
@@ -551,6 +607,7 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
auto& metricProducer1006 = *metricIt;
EXPECT_FALSE(metricProducer1006->isActive());
+ // Assert that all 3 metrics with activation are inactive and that the ttls were properly set.
EXPECT_FALSE(metricProducer1003->isActive());
const auto& activation1003 = metricProducer1003->mEventActivationMap.begin()->second;
EXPECT_EQ(100 * NS_PER_SEC, activation1003.ttl_ns);
@@ -566,12 +623,137 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
processor2->LoadMetricsActivationFromDisk();
+ // After loading activations from disk, assert that all 3 metrics are active.
EXPECT_TRUE(metricProducer1003->isActive());
EXPECT_EQ(timeBase2 + ttl3 - activation1003.ttl_ns, activation1003.activation_ns);
EXPECT_TRUE(metricProducer1005->isActive());
EXPECT_EQ(timeBase2 + ttl5 - activation1005.ttl_ns, activation1005.activation_ns);
EXPECT_TRUE(metricProducer1006->isActive());
EXPECT_EQ(timeBase2 + ttl6 - activation1006.ttl_ns, activation1003.activation_ns);
+
+ // Make sure no more broadcasts have happened.
+ EXPECT_EQ(broadcastCount, 1);
+}
+
+TEST(StatsLogProcessorTest, TestActivationOnBoot) {
+ int uid = 1111;
+
+ // Setup a simple config, no activation
+ StatsdConfig config1;
+ config1.set_id(12341);
+ config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+ auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
+ *config1.add_atom_matcher() = wakelockAcquireMatcher;
+
+ long metricId1 = 1234561;
+ long metricId2 = 1234562;
+ auto countMetric1 = config1.add_count_metric();
+ countMetric1->set_id(metricId1);
+ countMetric1->set_what(wakelockAcquireMatcher.id());
+ countMetric1->set_bucket(FIVE_MINUTES);
+
+ auto countMetric2 = config1.add_count_metric();
+ countMetric2->set_id(metricId2);
+ countMetric2->set_what(wakelockAcquireMatcher.id());
+ countMetric2->set_bucket(FIVE_MINUTES);
+
+ auto metric1Activation = config1.add_metric_activation();
+ metric1Activation->set_metric_id(metricId1);
+ metric1Activation->set_activation_type(MetricActivation::ACTIVATE_ON_BOOT);
+ auto metric1ActivationTrigger = metric1Activation->add_event_activation();
+ metric1ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
+ metric1ActivationTrigger->set_ttl_seconds(100);
+
+ ConfigKey cfgKey1(uid, 12341);
+ long timeBase1 = 1;
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
+
+ EXPECT_EQ(1, processor->mMetricsManagers.size());
+ auto it = processor->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor->mMetricsManagers.end());
+ auto& metricsManager1 = it->second;
+ EXPECT_TRUE(metricsManager1->isActive());
+
+ auto metricIt = metricsManager1->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId1) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
+ auto& metricProducer1 = *metricIt;
+ EXPECT_FALSE(metricProducer1->isActive());
+
+ metricIt = metricsManager1->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId2) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
+ auto& metricProducer2 = *metricIt;
+ EXPECT_TRUE(metricProducer2->isActive());
+
+ const auto& activation1 = metricProducer1->mEventActivationMap.begin()->second;
+ EXPECT_EQ(100 * NS_PER_SEC, activation1.ttl_ns);
+ EXPECT_EQ(0, activation1.activation_ns);
+ EXPECT_EQ(kNotActive, activation1.state);
+
+ std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
+ auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1);
+ processor->OnLogEvent(event.get());
+
+ EXPECT_FALSE(metricProducer1->isActive());
+ EXPECT_EQ(0, activation1.activation_ns);
+ EXPECT_EQ(kActiveOnBoot, activation1.state);
+
+ int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
+
+ processor->WriteMetricsActivationToDisk(shutDownTime);
+ EXPECT_TRUE(metricProducer1->isActive());
+ int64_t ttl1 = metricProducer1->getRemainingTtlNs(shutDownTime);
+ EXPECT_EQ(100 * NS_PER_SEC, ttl1);
+
+ long timeBase2 = 1000;
+ sp<StatsLogProcessor> processor2 =
+ CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
+
+ EXPECT_EQ(1, processor2->mMetricsManagers.size());
+ it = processor2->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor2->mMetricsManagers.end());
+ auto& metricsManager1001 = it->second;
+ EXPECT_TRUE(metricsManager1001->isActive());
+
+ metricIt = metricsManager1001->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId1) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
+ auto& metricProducer1001 = *metricIt;
+ EXPECT_FALSE(metricProducer1001->isActive());
+
+ metricIt = metricsManager1001->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId2) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
+ auto& metricProducer1002 = *metricIt;
+ EXPECT_TRUE(metricProducer1002->isActive());
+
+ const auto& activation1001 = metricProducer1001->mEventActivationMap.begin()->second;
+ EXPECT_EQ(100 * NS_PER_SEC, activation1001.ttl_ns);
+ EXPECT_EQ(0, activation1001.activation_ns);
+ EXPECT_EQ(kNotActive, activation1001.state);
+
+ processor2->LoadMetricsActivationFromDisk();
+
+ EXPECT_TRUE(metricProducer1001->isActive());
+ EXPECT_EQ(timeBase2 + ttl1 - activation1001.ttl_ns, activation1001.activation_ns);
}
#else
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index f0d9cf188661..c04a40cfebd9 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -45,7 +45,8 @@ TEST(UidMapTest, TestIsolatedUID) {
sp<AlarmMonitor> subscriberAlarmMonitor;
// Construct the processor with a dummy sendBroadcast function that does nothing.
StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
- [](const ConfigKey& key) { return true; });
+ [](const ConfigKey& key) { return true; },
+ [](const int&, const vector<int64_t>&) {return true;});
LogEvent addEvent(android::util::ISOLATED_UID_CHANGED, 1);
addEvent.write(100); // parent UID
addEvent.write(101); // isolated UID
diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
index 29e86f3f9456..85d8a5613a8b 100644
--- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
@@ -66,17 +66,42 @@ TEST(MetricActivationE2eTest, TestCountMetric) {
auto config = CreateStatsdConfig();
int64_t bucketStartTimeNs = 10000000000;
- int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-
- ConfigKey cfgKey;
- auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
- EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
- EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
- sp<MetricProducer> metricProducer =
- processor->mMetricsManagers.begin()->second->mAllMetricProducers[0];
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ sp<UidMap> m = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
+ vector<int64_t> activeConfigsBroadcast;
+
+ long timeBase1 = 1;
+ int broadcastCount = 0;
+ StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
+ bucketStartTimeNs, [](const ConfigKey& key) { return true; },
+ [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+ const vector<int64_t>& activeConfigs) {
+ broadcastCount++;
+ EXPECT_EQ(broadcastUid, uid);
+ activeConfigsBroadcast.clear();
+ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
+ activeConfigs.begin(), activeConfigs.end());
+ return true;
+ });
+
+ processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
+
+ EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
auto& eventActivationMap = metricProducer->mEventActivationMap;
+ EXPECT_FALSE(metricsManager->isActive());
EXPECT_FALSE(metricProducer->mIsActive);
// Two activations: one is triggered by battery saver mode (tracker index 0), the other is
// triggered by screen on event (tracker index 2).
@@ -93,13 +118,19 @@ TEST(MetricActivationE2eTest, TestCountMetric) {
std::unique_ptr<LogEvent> event;
event = CreateAppCrashEvent(111, bucketStartTimeNs + 5);
- processor->OnLogEvent(event.get());
+ processor.OnLogEvent(event.get());
+ EXPECT_FALSE(metricsManager->isActive());
EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 0);
// Activated by battery save mode.
event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
- processor->OnLogEvent(event.get());
+ processor.OnLogEvent(event.get());
+ EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 1);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0].state, ActivationState::kActive);
EXPECT_EQ(eventActivationMap[0].activation_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0].ttl_ns, 60 * 6 * NS_PER_SEC);
@@ -109,12 +140,13 @@ TEST(MetricActivationE2eTest, TestCountMetric) {
// First processed event.
event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
- processor->OnLogEvent(event.get());
+ processor.OnLogEvent(event.get());
// Activated by screen on event.
event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
bucketStartTimeNs + 20);
- processor->OnLogEvent(event.get());
+ processor.OnLogEvent(event.get());
+ EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0].state, ActivationState::kActive);
EXPECT_EQ(eventActivationMap[0].activation_ns, bucketStartTimeNs + 10);
@@ -126,7 +158,8 @@ TEST(MetricActivationE2eTest, TestCountMetric) {
// 2nd processed event.
// The activation by screen_on event expires, but the one by battery save mode is still active.
event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
- processor->OnLogEvent(event.get());
+ processor.OnLogEvent(event.get());
+ EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0].state, ActivationState::kActive);
EXPECT_EQ(eventActivationMap[0].activation_ns, bucketStartTimeNs + 10);
@@ -134,15 +167,21 @@ TEST(MetricActivationE2eTest, TestCountMetric) {
EXPECT_EQ(eventActivationMap[2].state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[2].activation_ns, bucketStartTimeNs + 20);
EXPECT_EQ(eventActivationMap[2].ttl_ns, 60 * 2 * NS_PER_SEC);
+ // No new broadcast since the config should still be active.
+ EXPECT_EQ(broadcastCount, 1);
// 3rd processed event.
event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
- processor->OnLogEvent(event.get());
+ processor.OnLogEvent(event.get());
// All activations expired.
event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
- processor->OnLogEvent(event.get());
+ processor.OnLogEvent(event.get());
+ EXPECT_FALSE(metricsManager->isActive());
EXPECT_FALSE(metricProducer->mIsActive);
+ // New broadcast since the config is no longer active.
+ EXPECT_EQ(broadcastCount, 2);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_EQ(eventActivationMap[0].state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[0].activation_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0].ttl_ns, 60 * 6 * NS_PER_SEC);
@@ -153,8 +192,12 @@ TEST(MetricActivationE2eTest, TestCountMetric) {
// Re-activate.
event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
- processor->OnLogEvent(event.get());
+ processor.OnLogEvent(event.get());
+ EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0].state, ActivationState::kNotActive);
EXPECT_EQ(eventActivationMap[0].activation_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0].ttl_ns, 60 * 6 * NS_PER_SEC);
@@ -163,11 +206,11 @@ TEST(MetricActivationE2eTest, TestCountMetric) {
EXPECT_EQ(eventActivationMap[2].ttl_ns, 60 * 2 * NS_PER_SEC);
event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
- processor->OnLogEvent(event.get());
+ processor.OnLogEvent(event.get());
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
+ processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
index 6069516e9666..1ff7982e1232 100644
--- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
+++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -133,6 +133,13 @@ TEST(StatsdStatsTest, TestSubStats) {
stats.noteMetricsReportSent(key, 0);
stats.noteMetricsReportSent(key, 0);
+ // activation_time_sec -> 2
+ stats.noteActiveStatusChanged(key, true);
+ stats.noteActiveStatusChanged(key, true);
+
+ // deactivation_time_sec -> 1
+ stats.noteActiveStatusChanged(key, false);
+
vector<uint8_t> output;
stats.dumpStats(&output, true); // Dump and reset stats
StatsdStatsReport report;
@@ -146,6 +153,8 @@ TEST(StatsdStatsTest, TestSubStats) {
EXPECT_EQ(123, configReport.data_drop_bytes(0));
EXPECT_EQ(3, configReport.dump_report_time_sec_size());
EXPECT_EQ(3, configReport.dump_report_data_size_size());
+ EXPECT_EQ(2, configReport.activation_time_sec_size());
+ EXPECT_EQ(1, configReport.deactivation_time_sec_size());
EXPECT_EQ(1, configReport.annotation_size());
EXPECT_EQ(123, configReport.annotation(0).field_int64());
EXPECT_EQ(456, configReport.annotation(0).field_int32());
@@ -259,6 +268,10 @@ TEST(StatsdStatsTest, TestPullAtomStats) {
stats.notePullDelay(android::util::DISK_SPACE, 3335L);
stats.notePull(android::util::DISK_SPACE);
stats.notePullFromCache(android::util::DISK_SPACE);
+ stats.notePullerCallbackRegistrationChanged(android::util::DISK_SPACE, true);
+ stats.notePullerCallbackRegistrationChanged(android::util::DISK_SPACE, false);
+ stats.notePullerCallbackRegistrationChanged(android::util::DISK_SPACE, true);
+
vector<uint8_t> output;
stats.dumpStats(&output, false);
@@ -276,6 +289,41 @@ TEST(StatsdStatsTest, TestPullAtomStats) {
EXPECT_EQ(3333L, report.pulled_atom_stats(0).max_pull_time_nanos());
EXPECT_EQ(2223L, report.pulled_atom_stats(0).average_pull_delay_nanos());
EXPECT_EQ(3335L, report.pulled_atom_stats(0).max_pull_delay_nanos());
+ EXPECT_EQ(2L, report.pulled_atom_stats(0).registered_count());
+ EXPECT_EQ(1L, report.pulled_atom_stats(0).unregistered_count());
+}
+
+TEST(StatsdStatsTest, TestAtomMetricsStats) {
+ StatsdStats stats;
+ time_t now = time(nullptr);
+ // old event, we get it from the stats buffer. should be ignored.
+ stats.noteBucketDropped(1000L);
+
+ stats.noteBucketBoundaryDelayNs(1000L, -1L);
+ stats.noteBucketBoundaryDelayNs(1000L, -10L);
+ stats.noteBucketBoundaryDelayNs(1000L, 2L);
+
+ stats.noteBucketBoundaryDelayNs(1001L, 1L);
+
+ vector<uint8_t> output;
+ stats.dumpStats(&output, false);
+ StatsdStatsReport report;
+ bool good = report.ParseFromArray(&output[0], output.size());
+ EXPECT_TRUE(good);
+
+ EXPECT_EQ(2, report.atom_metric_stats().size());
+
+ auto atomStats = report.atom_metric_stats(0);
+ EXPECT_EQ(1000L, atomStats.metric_id());
+ EXPECT_EQ(1L, atomStats.bucket_dropped());
+ EXPECT_EQ(-10L, atomStats.min_bucket_boundary_delay_ns());
+ EXPECT_EQ(2L, atomStats.max_bucket_boundary_delay_ns());
+
+ auto atomStats2 = report.atom_metric_stats(1);
+ EXPECT_EQ(1001L, atomStats2.metric_id());
+ EXPECT_EQ(0L, atomStats2.bucket_dropped());
+ EXPECT_EQ(0L, atomStats2.min_bucket_boundary_delay_ns());
+ EXPECT_EQ(1L, atomStats2.max_bucket_boundary_delay_ns());
}
TEST(StatsdStatsTest, TestAnomalyMonitor) {
@@ -305,6 +353,8 @@ TEST(StatsdStatsTest, TestTimestampThreshold) {
stats.noteDataDropped(key, timestamps[i]);
stats.noteBroadcastSent(key, timestamps[i]);
stats.noteMetricsReportSent(key, 0, timestamps[i]);
+ stats.noteActiveStatusChanged(key, true, timestamps[i]);
+ stats.noteActiveStatusChanged(key, false, timestamps[i]);
}
int32_t newTimestamp = 10000;
@@ -313,6 +363,8 @@ TEST(StatsdStatsTest, TestTimestampThreshold) {
stats.noteDataDropped(key, 123, 10000);
stats.noteBroadcastSent(key, 10000);
stats.noteMetricsReportSent(key, 0, 10000);
+ stats.noteActiveStatusChanged(key, true, 10000);
+ stats.noteActiveStatusChanged(key, false, 10000);
EXPECT_TRUE(stats.mConfigStats.find(key) != stats.mConfigStats.end());
const auto& configStats = stats.mConfigStats[key];
@@ -321,17 +373,23 @@ TEST(StatsdStatsTest, TestTimestampThreshold) {
EXPECT_EQ(maxCount, configStats->broadcast_sent_time_sec.size());
EXPECT_EQ(maxCount, configStats->data_drop_time_sec.size());
EXPECT_EQ(maxCount, configStats->dump_report_stats.size());
+ EXPECT_EQ(maxCount, configStats->activation_time_sec.size());
+ EXPECT_EQ(maxCount, configStats->deactivation_time_sec.size());
// the oldest timestamp is the second timestamp in history
EXPECT_EQ(1, configStats->broadcast_sent_time_sec.front());
- EXPECT_EQ(1, configStats->broadcast_sent_time_sec.front());
- EXPECT_EQ(1, configStats->broadcast_sent_time_sec.front());
+ EXPECT_EQ(1, configStats->data_drop_bytes.front());
+ EXPECT_EQ(1, configStats->dump_report_stats.front().first);
+ EXPECT_EQ(1, configStats->activation_time_sec.front());
+ EXPECT_EQ(1, configStats->deactivation_time_sec.front());
// the last timestamp is the newest timestamp.
EXPECT_EQ(newTimestamp, configStats->broadcast_sent_time_sec.back());
EXPECT_EQ(newTimestamp, configStats->data_drop_time_sec.back());
EXPECT_EQ(123, configStats->data_drop_bytes.back());
EXPECT_EQ(newTimestamp, configStats->dump_report_stats.back().first);
+ EXPECT_EQ(newTimestamp, configStats->activation_time_sec.back());
+ EXPECT_EQ(newTimestamp, configStats->deactivation_time_sec.back());
}
TEST(StatsdStatsTest, TestSystemServerCrash) {
diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
index b54096441d3f..b294cad1802c 100644
--- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
@@ -117,6 +117,7 @@ TEST(DurationMetricTrackerTest, TestNonSlicedCondition) {
DurationMetricProducer durationProducer(
kConfigKey, metric, 0 /* condition index */, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ durationProducer.mCondition = ConditionState::kFalse;
EXPECT_FALSE(durationProducer.mCondition);
EXPECT_FALSE(durationProducer.isConditionSliced());
@@ -140,6 +141,51 @@ TEST(DurationMetricTrackerTest, TestNonSlicedCondition) {
EXPECT_EQ(1LL, buckets2[0].mDuration);
}
+TEST(DurationMetricTrackerTest, TestNonSlicedConditionUnknownState) {
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+
+ DurationMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+ int tagId = 1;
+ LogEvent event1(tagId, bucketStartTimeNs + 1);
+ event1.init();
+ LogEvent event2(tagId, bucketStartTimeNs + 2);
+ event2.init();
+ LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 1);
+ event3.init();
+ LogEvent event4(tagId, bucketStartTimeNs + bucketSizeNs + 3);
+ event4.init();
+
+ FieldMatcher dimensions;
+ DurationMetricProducer durationProducer(
+ kConfigKey, metric, 0 /* condition index */, 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+ EXPECT_EQ(ConditionState::kUnknown, durationProducer.mCondition);
+ EXPECT_FALSE(durationProducer.isConditionSliced());
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
+ durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+ EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
+ const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets2.size());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
+ EXPECT_EQ(1LL, buckets2[0].mDuration);
+}
+
TEST(DurationMetricTrackerTest, TestSumDurationWithUpgrade) {
/**
* The duration starts from the first bucket, through the two partial buckets (10-70sec),
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index ae3cdbcb5eb4..7e7ffeda8053 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -2176,7 +2176,7 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange) {
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.mCondition = true;
+ valueProducer.mCondition = ConditionState::kTrue;
vector<shared_ptr<LogEvent>> allData;
valueProducer.onDataPulled(allData, /** succeed */ false, bucketStartTimeNs);
@@ -2226,7 +2226,7 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded) {
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.mCondition = false;
+ valueProducer.mCondition = ConditionState::kFalse;
// Max delay is set to 0 so pull will exceed max delay.
valueProducer.onConditionChanged(true, bucketStartTimeNs + 1);
@@ -2257,7 +2257,7 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate) {
eventMatcherWizard, tagId, bucket2StartTimeNs,
bucket2StartTimeNs, pullerManager);
- valueProducer.mCondition = false;
+ valueProducer.mCondition = ConditionState::kFalse;
// Event should be skipped since it is from previous bucket.
// Pull should not be called.
@@ -2299,7 +2299,7 @@ TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange) {
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.mCondition = false;
+ valueProducer.mCondition = ConditionState::kFalse;
valueProducer.mHasGlobalBase = false;
valueProducer.onConditionChanged(true, bucketStartTimeNs + 1);
@@ -2351,7 +2351,7 @@ TEST(ValueMetricProducerTest, TestInvalidBucketWhenOneConditionFailed) {
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.mCondition = true;
+ valueProducer.mCondition = ConditionState::kTrue;
// Bucket start.
vector<shared_ptr<LogEvent>> allData;
@@ -2390,6 +2390,51 @@ TEST(ValueMetricProducerTest, TestInvalidBucketWhenOneConditionFailed) {
EXPECT_EQ(true, valueProducer.mHasGlobalBase);
}
+TEST(ValueMetricProducerTest, TestInvalidBucketWhenGuardRailHit) {
+ ValueMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.mutable_value_field()->set_field(tagId);
+ metric.mutable_value_field()->add_child()->set_field(2);
+ metric.mutable_dimensions_in_what()->set_field(tagId);
+ metric.mutable_dimensions_in_what()->add_child()->set_field(1);
+ metric.set_condition(StringToId("SCREEN_ON"));
+ metric.set_max_pull_delay_sec(INT_MAX);
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // First onConditionChanged
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ for (int i = 0; i < 2000; i++) {
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+ event->write(i);
+ event->write(i);
+ event->init();
+ data->push_back(event);
+ }
+ return true;
+ }));
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+ eventMatcherWizard, tagId, bucketStartTimeNs,
+ bucketStartTimeNs, pullerManager);
+
+ valueProducer.mCondition = ConditionState::kFalse;
+ valueProducer.onConditionChanged(true, bucket2StartTimeNs + 2);
+ EXPECT_EQ(true, valueProducer.mCurrentBucketIsInvalid);
+ EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
+}
+
TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed) {
ValueMetric metric;
metric.set_id(metricId);
@@ -2436,7 +2481,7 @@ TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed) {
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.mCondition = true;
+ valueProducer.mCondition = ConditionState::kTrue;
// Bucket start.
vector<shared_ptr<LogEvent>> allData;
@@ -2519,7 +2564,7 @@ TEST(ValueMetricProducerTest, TestInvalidBucketWhenLastPullFailed) {
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.mCondition = true;
+ valueProducer.mCondition = ConditionState::kTrue;
// Bucket start.
vector<shared_ptr<LogEvent>> allData;
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index b8b1a1db2c12..2c4f3c7692c9 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -461,7 +461,8 @@ sp<StatsLogProcessor> CreateStatsLogProcessor(const int64_t timeBaseNs, const in
[](const sp<IStatsCompanionService>&){});
sp<StatsLogProcessor> processor =
new StatsLogProcessor(uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseNs, [](const ConfigKey&) { return true; });
+ timeBaseNs, [](const ConfigKey&) { return true; },
+ [](const int&, const vector<int64_t>&) {return true;});
processor->OnConfigUpdated(currentTimeNs, key, config);
return processor;
}
@@ -826,4 +827,4 @@ void backfillStartEndTimestamp(ConfigMetricsReportList *config_report_list) {
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/tests/storage/StorageManager_test.cpp b/cmds/statsd/tests/storage/StorageManager_test.cpp
new file mode 100644
index 000000000000..f66de0518f80
--- /dev/null
+++ b/cmds/statsd/tests/storage/StorageManager_test.cpp
@@ -0,0 +1,52 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include "src/storage/StorageManager.h"
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using namespace testing;
+using std::make_shared;
+using std::shared_ptr;
+using std::vector;
+using testing::Contains;
+
+TEST(StorageManagerTest, TrainInfoReadWriteTest) {
+ InstallTrainInfo trainInfo;
+ trainInfo.trainVersionCode = 12345;
+ const char* expIds = "test_ids";
+ trainInfo.experimentIds.assign(expIds, expIds + strlen(expIds));
+
+ StorageManager::writeTrainInfo(trainInfo.trainVersionCode, trainInfo.experimentIds);
+
+ InstallTrainInfo result;
+ StorageManager::readTrainInfo(result);
+ EXPECT_EQ(trainInfo.trainVersionCode, result.trainVersionCode);
+ EXPECT_EQ(trainInfo.experimentIds.size(), result.experimentIds.size());
+ EXPECT_EQ(trainInfo.experimentIds, result.experimentIds);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 010e4478459d..dc2ed4cc0d69 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -542,8 +542,6 @@ Landroid/net/IConnectivityManager;->getTetherableWifiRegexs()[Ljava/lang/String;
Landroid/net/IConnectivityManager;->getTetheredIfaces()[Ljava/lang/String;
Landroid/net/IConnectivityManager;->getTetheringErroredIfaces()[Ljava/lang/String;
Landroid/net/IConnectivityManager;->startLegacyVpn(Lcom/android/internal/net/VpnProfile;)V
-Landroid/net/INetd$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetd;
-Landroid/net/INetd;->interfaceAddAddress(Ljava/lang/String;Ljava/lang/String;I)V
Landroid/net/INetworkManagementEventObserver$Stub;-><init>()V
Landroid/net/INetworkPolicyListener$Stub;-><init>()V
Landroid/net/INetworkPolicyManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkPolicyManager;
@@ -2439,7 +2437,6 @@ Lcom/android/internal/telephony/cat/CatService;->isStkAppInstalled()Z
Lcom/android/internal/telephony/cat/CatService;->mCmdIf:Lcom/android/internal/telephony/CommandsInterface;
Lcom/android/internal/telephony/cat/CatService;->mContext:Landroid/content/Context;
Lcom/android/internal/telephony/cat/CatService;->mCurrntCmd:Lcom/android/internal/telephony/cat/CatCmdMessage;
-Lcom/android/internal/telephony/cat/CatService;->mHandlerThread:Landroid/os/HandlerThread;
Lcom/android/internal/telephony/cat/CatService;->mMenuCmd:Lcom/android/internal/telephony/cat/CatCmdMessage;
Lcom/android/internal/telephony/cat/CatService;->mMsgDecoder:Lcom/android/internal/telephony/cat/RilMessageDecoder;
Lcom/android/internal/telephony/cat/CatService;->mSlotId:I
@@ -2826,7 +2823,6 @@ Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->reset()V
Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;-><init>()V
Lcom/android/internal/telephony/GsmCdmaCall;->attachFake(Lcom/android/internal/telephony/Connection;Lcom/android/internal/telephony/Call$State;)V
Lcom/android/internal/telephony/GsmCdmaCallTracker;->clearDisconnected()V
-Lcom/android/internal/telephony/GsmCdmaCallTracker;->dialThreeWay(Ljava/lang/String;)Lcom/android/internal/telephony/Connection;
Lcom/android/internal/telephony/GsmCdmaCallTracker;->disableDataCallInEmergencyCall(Ljava/lang/String;)V
Lcom/android/internal/telephony/GsmCdmaCallTracker;->fakeHoldForegroundBeforeDial()V
Lcom/android/internal/telephony/GsmCdmaCallTracker;->getPhone()Lcom/android/internal/telephony/GsmCdmaPhone;
diff --git a/core/java/android/accessibilityservice/OWNERS b/core/java/android/accessibilityservice/OWNERS
new file mode 100644
index 000000000000..265674a74b7e
--- /dev/null
+++ b/core/java/android/accessibilityservice/OWNERS
@@ -0,0 +1,3 @@
+svetoslavganov@google.com
+pweaver@google.com
+rhedjao@google.com
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 0eadd1dcd903..5f778da44a1c 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -65,6 +65,7 @@ import android.net.Uri;
import android.os.BadParcelableException;
import android.os.Build;
import android.os.Bundle;
+import android.os.GraphicsEnvironment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -7708,6 +7709,8 @@ public class Activity extends ContextThemeWrapper
}
}
+ GraphicsEnvironment.getInstance().showAngleInUseDialogBox(this);
+
mActivityTransitionState.enterReady(this);
dispatchActivityPostStarted();
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index db3b720642aa..5d4f988c3630 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -55,6 +55,7 @@ import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
+import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
@@ -68,6 +69,7 @@ import android.util.DisplayMetrics;
import android.util.Singleton;
import android.util.Size;
+import com.android.internal.app.LocalePicker;
import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.os.RoSystemProperties;
import com.android.internal.os.TransferPipe;
@@ -84,7 +86,9 @@ import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
+import java.util.Locale;
/**
* <p>
@@ -2019,8 +2023,9 @@ public class ActivityManager {
return getTaskService().isActivityStartAllowedOnDisplay(displayId, intent,
intent.resolveTypeIfNeeded(context.getContentResolver()), context.getUserId());
} catch (RemoteException e) {
- throw new RuntimeException("Failure from system", e);
+ e.rethrowFromSystemServer();
}
+ return false;
}
/**
@@ -3450,6 +3455,35 @@ public class ActivityManager {
}
/**
+ * Sets the current locales of the device. Calling app must have the permission
+ * {@code android.permission.CHANGE_CONFIGURATION} and
+ * {@code android.permission.WRITE_SETTINGS}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public void setDeviceLocales(@NonNull LocaleList locales) {
+ LocalePicker.updateLocales(locales);
+ }
+
+ /**
+ * Returns a list of supported locales by this system. It includes all locales that are
+ * selectable by the user, potentially including locales that the framework does not have
+ * translated resources for. To get locales that the framework has translated resources for, use
+ * {@code Resources.getSystem().getAssets().getLocales()} instead.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @NonNull Collection<Locale> getSupportedLocales() {
+ ArrayList<Locale> locales = new ArrayList<>();
+ for (String localeTag : LocalePicker.getSupportedLocales(mContext)) {
+ locales.add(Locale.forLanguageTag(localeTag));
+ }
+ return locales;
+ }
+
+ /**
* Get the device configuration attributes.
*/
public ConfigurationInfo getDeviceConfigurationInfo() {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 64b94a946489..f76f7b9a7fc7 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -848,6 +848,7 @@ public class AppOpsManager {
/** @hide Has a legacy (non-isolated) view of storage. */
public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage";
/** @hide Interact with accessibility. */
+ @SystemApi
public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility";
// Warning: If an permission is added here it also has to be added to
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 1a728c12e138..6908ca27480c 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2101,7 +2101,8 @@ class ContextImpl extends Context {
}
private static Resources createResources(IBinder activityToken, LoadedApk pi, String splitName,
- int displayId, Configuration overrideConfig, CompatibilityInfo compatInfo) {
+ int displayId, Configuration overrideConfig, CompatibilityInfo compatInfo,
+ String[] overlayDirs) {
final String[] splitResDirs;
final ClassLoader classLoader;
try {
@@ -2113,7 +2114,7 @@ class ContextImpl extends Context {
return ResourcesManager.getInstance().getResources(activityToken,
pi.getResDir(),
splitResDirs,
- pi.getOverlayDirs(),
+ overlayDirs,
pi.getApplicationInfo().sharedLibraryFiles,
displayId,
overrideConfig,
@@ -2131,9 +2132,11 @@ class ContextImpl extends Context {
new UserHandle(UserHandle.getUserId(application.uid)), flags, null, null);
final int displayId = getDisplayId();
-
+ // overlayDirs is retrieved directly from ApplicationInfo since ActivityThread may have
+ // a LoadedApk containing Resources with stale overlays for a remote application.
+ final String[] overlayDirs = application.resourceDirs;
c.setResources(createResources(mActivityToken, pi, null, displayId, null,
- getDisplayAdjustments(displayId).getCompatibilityInfo()));
+ getDisplayAdjustments(displayId).getCompatibilityInfo(), overlayDirs));
if (c.mResources != null) {
return c;
}
@@ -2168,7 +2171,7 @@ class ContextImpl extends Context {
final int displayId = getDisplayId();
c.setResources(createResources(mActivityToken, pi, null, displayId, null,
- getDisplayAdjustments(displayId).getCompatibilityInfo()));
+ getDisplayAdjustments(displayId).getCompatibilityInfo(), pi.getOverlayDirs()));
if (c.mResources != null) {
return c;
}
@@ -2218,7 +2221,8 @@ class ContextImpl extends Context {
final int displayId = getDisplayId();
context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId,
- overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo()));
+ overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo(),
+ mPackageInfo.getOverlayDirs()));
return context;
}
@@ -2233,7 +2237,8 @@ class ContextImpl extends Context {
final int displayId = display.getDisplayId();
context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId,
- null, getDisplayAdjustments(displayId).getCompatibilityInfo()));
+ null, getDisplayAdjustments(displayId).getCompatibilityInfo(),
+ mPackageInfo.getOverlayDirs()));
context.mDisplay = display;
return context;
}
@@ -2416,7 +2421,7 @@ class ContextImpl extends Context {
ContextImpl context = new ContextImpl(null, systemContext.mMainThread, packageInfo, null,
null, null, 0, null, null);
context.setResources(createResources(null, packageInfo, null, displayId, null,
- packageInfo.getCompatibilityInfo()));
+ packageInfo.getCompatibilityInfo(), packageInfo.getOverlayDirs()));
context.updateDisplay(displayId);
return context;
}
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index db6ad3df17b0..2b765b2284e7 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -247,8 +247,20 @@ interface IActivityTaskManager {
boolean preserveWindows, boolean animate, int animationDuration);
boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop,
boolean animate, in Rect initialBounds, boolean showRecents);
-
-
+ /**
+ * Use the offset to adjust the stack boundary with animation.
+ *
+ * @param stackId Id of the stack to adjust.
+ * @param compareBounds Offset is only applied if the current pinned stack bounds is equal to
+ * the compareBounds.
+ * @param xOffset The horizontal offset.
+ * @param yOffset The vertical offset.
+ * @param animationDuration The duration of the resize animation in milliseconds or -1 if the
+ * default animation duration should be used.
+ * @throws RemoteException
+ */
+ void offsetPinnedStackBounds(int stackId, in Rect compareBounds, int xOffset, int yOffset,
+ int animationDuration);
/**
* Removes stacks in the input windowing modes from the system if they are of activity type
* ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index f522d71afd08..17f645dfbf23 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -125,7 +125,7 @@ public class KeyguardManager {
public static final int RESULT_ALTERNATE = 1;
/**
- * @deprecated see {@link BiometricPrompt.Builder#setEnableFallback(boolean)}
+ * @deprecated see {@link BiometricPrompt.Builder#setAllowDeviceCredential(boolean)}
*
* Get an intent to prompt the user to confirm credentials (pin, pattern, password or biometrics
* if enrolled) for the current user of the device. The caller is expected to launch this
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index d46dbedfe8c2..5c4c0052cfbb 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -870,8 +870,9 @@ public final class LoadedApk {
}
}
- // /vendor/lib, /odm/lib and /product/lib are added to the native lib search
- // paths of the classloader. Note that this is done AFTER the classloader is
+ // /aepx/com.android.runtime/lib, /vendor/lib, /odm/lib and /product/lib
+ // are added to the native lib search paths of the classloader.
+ // Note that this is done AFTER the classloader is
// created by ApplicationLoaders.getDefault().getClassLoader(...). The
// reason is because if we have added the paths when creating the classloader
// above, the paths are also added to the search path of the linker namespace
@@ -888,8 +889,11 @@ public final class LoadedApk {
// System.loadLibrary(). In order to prevent the problem, we explicitly
// add the paths only to the classloader, and not to the native loader
// (linker namespace).
- List<String> extraLibPaths = new ArrayList<>(3);
+ List<String> extraLibPaths = new ArrayList<>(4);
String abiSuffix = VMRuntime.getRuntime().is64Bit() ? "64" : "";
+ if (!defaultSearchPaths.contains("/apex/com.android.runtime/lib")) {
+ extraLibPaths.add("/apex/com.android.runtime/lib" + abiSuffix);
+ }
if (!defaultSearchPaths.contains("/vendor/lib")) {
extraLibPaths.add("/vendor/lib" + abiSuffix);
}
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index 3119b37a686e..7746148d325a 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -24,6 +24,7 @@ import android.annotation.SystemApi;
import android.content.Context;
import android.os.IBinder;
import android.os.IStatsManager;
+import android.os.IStatsPullerCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.AndroidException;
@@ -408,6 +409,39 @@ public final class StatsManager {
}
}
+ /**
+ * Registers a callback for an atom when that atom is to be pulled. The stats service will
+ * invoke pullData in the callback when the stats service determines that this atom needs to be
+ * pulled. Currently, this only works for atoms with tags above 100,000 that do not have a uid.
+ *
+ * @param atomTag The tag of the atom for this puller callback. Must be at least 100000.
+ * @param callback The callback to be invoked when the stats service pulls the atom.
+ * @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
+ *
+ * @hide
+ */
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
+ public void setPullerCallback(int atomTag, IStatsPullerCallback callback)
+ throws StatsUnavailableException {
+ synchronized (this) {
+ try {
+ IStatsManager service = getIStatsManagerLocked();
+ if (callback == null) {
+ service.unregisterPullerCallback(atomTag, mContext.getOpPackageName());
+ } else {
+ service.registerPullerCallback(atomTag, callback,
+ mContext.getOpPackageName());
+ }
+
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to connect to statsd when registering data listener.");
+ throw new StatsUnavailableException("could not connect", e);
+ } catch (SecurityException e) {
+ throw new StatsUnavailableException(e.getMessage(), e);
+ }
+ }
+ }
+
private class StatsdDeathRecipient implements IBinder.DeathRecipient {
@Override
public void binderDied() {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 807b7f2ac349..cca8bd00b646 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -101,7 +101,6 @@ import android.net.IConnectivityManager;
import android.net.IEthernetManager;
import android.net.IIpMemoryStore;
import android.net.IIpSecService;
-import android.net.INetd;
import android.net.INetworkPolicyManager;
import android.net.IpMemoryStore;
import android.net.IpSecManager;
@@ -330,11 +329,10 @@ final class SystemServiceRegistry {
return new ConnectivityManager(context, service);
}});
- registerService(Context.NETD_SERVICE, INetd.class, new StaticServiceFetcher<INetd>() {
+ registerService(Context.NETD_SERVICE, IBinder.class, new StaticServiceFetcher<IBinder>() {
@Override
- public INetd createService() throws ServiceNotFoundException {
- return INetd.Stub.asInterface(
- ServiceManager.getServiceOrThrow(Context.NETD_SERVICE));
+ public IBinder createService() throws ServiceNotFoundException {
+ return ServiceManager.getServiceOrThrow(Context.NETD_SERVICE);
}
});
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 077b177be930..dd00e5a74382 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -97,6 +97,12 @@ public class TaskInfo {
public long lastActiveTime;
/**
+ * The id of the display this task is associated with.
+ * @hide
+ */
+ public int displayId;
+
+ /**
* The recent activity values for the highest activity in the stack to have set the values.
* {@link Activity#setTaskDescription(android.app.ActivityManager.TaskDescription)}.
*/
@@ -152,6 +158,7 @@ public class TaskInfo {
userId = source.readInt();
stackId = source.readInt();
taskId = source.readInt();
+ displayId = source.readInt();
isRunning = source.readBoolean();
baseIntent = source.readInt() != 0
? Intent.CREATOR.createFromParcel(source)
@@ -179,6 +186,7 @@ public class TaskInfo {
dest.writeInt(userId);
dest.writeInt(stackId);
dest.writeInt(taskId);
+ dest.writeInt(displayId);
dest.writeBoolean(isRunning);
if (baseIntent != null) {
@@ -209,6 +217,7 @@ public class TaskInfo {
@Override
public String toString() {
return "TaskInfo{userId=" + userId + " stackId=" + stackId + " taskId=" + taskId
+ + " displayId=" + displayId
+ " isRunning=" + isRunning
+ " baseIntent=" + baseIntent + " baseActivity=" + baseActivity
+ " topActivity=" + topActivity + " origActivity=" + origActivity
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 3ff6973a09ff..806536b6947c 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1376,7 +1376,7 @@ public class DevicePolicyManager {
* complexity, and use this activity with extra {@link #EXTRA_PASSWORD_COMPLEXITY} to suggest
* to users how complex the app wants the new screen lock to be. Note that both {@link
* #getPasswordComplexity()} and the extra {@link #EXTRA_PASSWORD_COMPLEXITY} require the
- * calling app to have the permission {@link permission#GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY}.
+ * calling app to have the permission {@link permission#REQUEST_SCREEN_LOCK_COMPLEXITY}.
*
* <p>If the intent is launched from within a managed profile with a profile
* owner built against {@link android.os.Build.VERSION_CODES#M} or before,
@@ -1404,7 +1404,7 @@ public class DevicePolicyManager {
*
* <p>If an invalid value is used, it will be treated as {@link #PASSWORD_COMPLEXITY_NONE}.
*/
- @RequiresPermission(android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY)
+ @RequiresPermission(android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY)
public static final String EXTRA_PASSWORD_COMPLEXITY =
"android.app.extra.PASSWORD_COMPLEXITY";
@@ -2125,7 +2125,7 @@ public class DevicePolicyManager {
* Callback used in {@link #installSystemUpdate} to indicate that there was an error while
* trying to install an update.
*/
- public abstract static class InstallUpdateCallback {
+ public abstract static class InstallSystemUpdateCallback {
/** Represents an unknown error while trying to install an update. */
public static final int UPDATE_ERROR_UNKNOWN = 1;
@@ -2144,7 +2144,12 @@ public class DevicePolicyManager {
/** Represents the battery being too low to apply an update. */
public static final int UPDATE_ERROR_BATTERY_LOW = 5;
- /** Method invoked when there was an error while installing an update. */
+ /**
+ * Method invoked when there was an error while installing an update.
+ *
+ * <p>The given error message is not intended to be user-facing. It is intended to be
+ * reported back to the IT admin to be read.
+ */
public void onInstallUpdateError(
@InstallUpdateCallbackErrorConstants int errorCode, String errorMessage) {
}
@@ -2154,11 +2159,11 @@ public class DevicePolicyManager {
* @hide
*/
@IntDef(prefix = { "UPDATE_ERROR_" }, value = {
- InstallUpdateCallback.UPDATE_ERROR_UNKNOWN,
- InstallUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION,
- InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID,
- InstallUpdateCallback.UPDATE_ERROR_FILE_NOT_FOUND,
- InstallUpdateCallback.UPDATE_ERROR_BATTERY_LOW
+ InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN,
+ InstallSystemUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION,
+ InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID,
+ InstallSystemUpdateCallback.UPDATE_ERROR_FILE_NOT_FOUND,
+ InstallSystemUpdateCallback.UPDATE_ERROR_BATTERY_LOW
})
@Retention(RetentionPolicy.SOURCE)
public @interface InstallUpdateCallbackErrorConstants {}
@@ -3346,10 +3351,10 @@ public class DevicePolicyManager {
*
* @throws IllegalStateException if the user is not unlocked.
* @throws SecurityException if the calling application does not have the permission
- * {@link permission#GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY}
+ * {@link permission#REQUEST_SCREEN_LOCK_COMPLEXITY}
*/
@PasswordComplexity
- @RequiresPermission(android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY)
+ @RequiresPermission(android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY)
public int getPasswordComplexity() {
throwIfParentInstance("getPasswordComplexity");
if (mService == null) {
@@ -4618,6 +4623,10 @@ public class DevicePolicyManager {
* <p>If the installer must have access to the credentials, call
* {@link #installKeyPair(ComponentName, PrivateKey, Certificate[], String, boolean)} instead.
*
+ * <p>Note: If the provided {@code alias} is of an existing alias, all former grants that apps
+ * have been given to access the key and certificates associated with this alias will be
+ * revoked.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
* {@code null} if calling from a delegated certificate installer.
* @param privKey The private key to install.
@@ -4645,6 +4654,10 @@ public class DevicePolicyManager {
* immediately, without user approval. It is a best practice not to request this unless strictly
* necessary since it opens up additional security vulnerabilities.
*
+ * <p>Note: If the provided {@code alias} is of an existing alias, all former grants that apps
+ * have been given to access the key and certificates associated with this alias will be
+ * revoked.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
* {@code null} if calling from a delegated certificate installer.
* @param privKey The private key to install.
@@ -4685,6 +4698,10 @@ public class DevicePolicyManager {
* <p>Include {@link #INSTALLKEY_SET_USER_SELECTABLE} in the {@code flags} argument to allow
* the user to select the key from a dialog.
*
+ * <p>Note: If the provided {@code alias} is of an existing alias, all former grants that apps
+ * have been given to access the key and certificates associated with this alias will be
+ * revoked.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
* {@code null} if calling from a delegated certificate installer.
* @param privKey The private key to install.
@@ -4761,6 +4778,10 @@ public class DevicePolicyManager {
* <p>Because this method might take several seconds to complete, it should only be called from
* a worker thread. This method returns {@code null} when called from the main thread.
*
+ * <p>Note: If the provided {@code alias} is of an existing alias, all former grants that apps
+ * have been given to access the key and certificates associated with this alias will be
+ * revoked.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
* {@code null} if calling from a delegated certificate installer.
* @param algorithm The key generation algorithm, see {@link java.security.KeyPairGenerator}.
@@ -9628,7 +9649,7 @@ public class DevicePolicyManager {
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param enabled {@code true} to enable the backup service, {@code false} to disable it.
- * @throws SecurityException if {@code admin} is not a device owner.
+ * @throws SecurityException if {@code admin} is not a device owner or a profile owner.
*/
public void setBackupServiceEnabled(@NonNull ComponentName admin, boolean enabled) {
throwIfParentInstance("setBackupServiceEnabled");
@@ -10415,9 +10436,9 @@ public class DevicePolicyManager {
* doesn't necessarily mean that the update has been applied successfully. The caller should
* additionally check the system version with {@link android.os.Build#FINGERPRINT} or {@link
* android.os.Build.VERSION}. If an error occurs during processing the OTA before the reboot,
- * the caller will be notified by {@link InstallUpdateCallback}. If device does not have
+ * the caller will be notified by {@link InstallSystemUpdateCallback}. If device does not have
* sufficient battery level, the installation will fail with error {@link
- * InstallUpdateCallback#UPDATE_ERROR_BATTERY_LOW}.
+ * InstallSystemUpdateCallback#UPDATE_ERROR_BATTERY_LOW}.
*
* @param admin The {@link DeviceAdminReceiver} that this request is associated with.
* @param updateFilePath An Uri of the file that contains the update. The file should be
@@ -10429,7 +10450,7 @@ public class DevicePolicyManager {
public void installSystemUpdate(
@NonNull ComponentName admin, @NonNull Uri updateFilePath,
@NonNull @CallbackExecutor Executor executor,
- @NonNull InstallUpdateCallback callback) {
+ @NonNull InstallSystemUpdateCallback callback) {
throwIfParentInstance("installUpdate");
if (mService == null) {
return;
@@ -10449,19 +10470,20 @@ public class DevicePolicyManager {
} catch (FileNotFoundException e) {
Log.w(TAG, e);
executeCallback(
- InstallUpdateCallback.UPDATE_ERROR_FILE_NOT_FOUND, Log.getStackTraceString(e),
+ InstallSystemUpdateCallback.UPDATE_ERROR_FILE_NOT_FOUND,
+ Log.getStackTraceString(e),
executor, callback);
} catch (IOException e) {
Log.w(TAG, e);
executeCallback(
- InstallUpdateCallback.UPDATE_ERROR_UNKNOWN, Log.getStackTraceString(e),
+ InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN, Log.getStackTraceString(e),
executor, callback);
}
}
private void executeCallback(int errorCode, String errorMessage,
@NonNull @CallbackExecutor Executor executor,
- @NonNull InstallUpdateCallback callback) {
+ @NonNull InstallSystemUpdateCallback callback) {
executor.execute(() -> callback.onInstallUpdateError(errorCode, errorMessage));
}
@@ -10521,6 +10543,8 @@ public class DevicePolicyManager {
* @hide
*/
@SystemApi
+ @RequiresPermission(value = android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS,
+ conditional = true)
public void setProfileOwnerCanAccessDeviceIdsForUser(
@NonNull ComponentName who, @NonNull UserHandle userHandle) {
if (mService == null) {
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index 04d5c5aaa1d5..edd3ef983945 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -69,6 +69,22 @@ public final class RoleManager {
private static final String LOG_TAG = RoleManager.class.getSimpleName();
/**
+ * The name of the assistant app role.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
+
+ /**
+ * The name of the browser role.
+ *
+ * @see Intent#CATEGORY_APP_BROWSER
+ */
+ public static final String ROLE_BROWSER = "android.app.role.BROWSER";
+
+ /**
* The name of the dialer role.
*
* @see Intent#ACTION_DIAL
@@ -83,18 +99,18 @@ public final class RoleManager {
public static final String ROLE_SMS = "android.app.role.SMS";
/**
- * The name of the browser role.
+ * The name of the emergency role
*
- * @see Intent#CATEGORY_APP_BROWSER
+ * @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE
*/
- public static final String ROLE_BROWSER = "android.app.role.BROWSER";
+ public static final String ROLE_EMERGENCY = "android.app.role.EMERGENCY";
/**
- * The name of the gallery role.
+ * The name of the home role.
*
- * @see Intent#CATEGORY_APP_GALLERY
+ * @see Intent#CATEGORY_HOME
*/
- public static final String ROLE_GALLERY = "android.app.role.GALLERY";
+ public static final String ROLE_HOME = "android.app.role.HOME";
/**
* The name of the music player role.
@@ -104,18 +120,11 @@ public final class RoleManager {
public static final String ROLE_MUSIC = "android.app.role.MUSIC";
/**
- * The name of the home role.
- *
- * @see Intent#CATEGORY_HOME
- */
- public static final String ROLE_HOME = "android.app.role.HOME";
-
- /**
- * The name of the emergency role
+ * The name of the gallery role.
*
- * @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE
+ * @see Intent#CATEGORY_APP_GALLERY
*/
- public static final String ROLE_EMERGENCY = "android.app.role.EMERGENCY";
+ public static final String ROLE_GALLERY = "android.app.role.GALLERY";
/**
* The name of the car mode dialer app role.
@@ -173,15 +182,6 @@ public final class RoleManager {
public static final String ROLE_CALL_COMPANION = "android.app.role.CALL_COMPANION";
/**
- * The name of the assistant app role.
- *
- * @hide
- */
- @SystemApi
- @TestApi
- public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
-
- /**
* @hide
*/
@IntDef(flag = true, value = { MANAGE_HOLDERS_FLAG_DONT_KILL_APP })
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 51397a243420..dc5bdc673249 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -745,7 +745,11 @@ public final class UsageStatsManager {
* Registering an {@code observerId} that was already registered will override the previous one.
* No more than 1000 unique {@code observerId} may be registered by a single uid
* at any one time.
- * A limit may be unregistered via {@link #unregisterAppUsageLimitObserver}
+ * A limit is not cleared when the usage time is exceeded. It needs to be unregistered via
+ * {@link #unregisterAppUsageLimitObserver}.
+ * <p>
+ * Note: usage limits are not persisted in the system and are cleared on reboots. Callers
+ * must reset any limits that they need on reboots.
* <p>
* This method is similar to {@link #registerAppUsageObserver}, but the usage limit set here
* will be visible to the launcher so that it can report the limit to the user and how much
@@ -757,12 +761,15 @@ public final class UsageStatsManager {
* @param observedEntities The list of packages and token to observe for usage time. Cannot be
* null and must include at least one package or token.
* @param timeLimit The total time the set of apps can be in the foreground before the
- * callbackIntent is delivered. Must be at least one minute.
+ * callbackIntent is delivered. Must be at least one minute. Note: a limit of
+ * 0 can be set to indicate that the user has already exhausted the limit for
+ * a group, in which case, the given {@code callbackIntent} will be ignored.
* @param timeUnit The unit for time specified in {@code timeLimit}. Cannot be null.
- * @param callbackIntent The PendingIntent that will be dispatched when the usage limit is
+ * @param callbackIntent The PendingIntent that will be dispatched when the usage limit is
* exceeded by the group of apps. The delivered Intent will also contain
* the extras {@link #EXTRA_OBSERVER_ID}, {@link #EXTRA_TIME_LIMIT} and
- * {@link #EXTRA_TIME_USED}. Cannot be null.
+ * {@link #EXTRA_TIME_USED}. Cannot be {@code null} unless the observer is
+ * being registered with a {@code timeLimit} of 0.
* @throws SecurityException if the caller doesn't have both SUSPEND_APPS and OBSERVE_APP_USAGE
* permissions.
* @hide
@@ -772,7 +779,7 @@ public final class UsageStatsManager {
android.Manifest.permission.SUSPEND_APPS,
android.Manifest.permission.OBSERVE_APP_USAGE})
public void registerAppUsageLimitObserver(int observerId, @NonNull String[] observedEntities,
- long timeLimit, @NonNull TimeUnit timeUnit, @NonNull PendingIntent callbackIntent) {
+ long timeLimit, @NonNull TimeUnit timeUnit, PendingIntent callbackIntent) {
try {
mService.registerAppUsageLimitObserver(observerId, observedEntities,
timeUnit.toMillis(timeLimit), callbackIntent, mContext.getOpPackageName());
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index f1bfe8671eec..7672ccfcd995 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -2998,7 +2998,9 @@ public abstract class ContentResolver implements ContentInterface {
*
* @param key the key to add
* @param value the value to add
+ * {@hide}
*/
+ @SystemApi
public void putCache(Uri key, Bundle value) {
try {
getContentService().putCache(mContext.getPackageName(), key, value,
@@ -3014,7 +3016,9 @@ public abstract class ContentResolver implements ContentInterface {
* @param key the key to get the value
* @return the matched value. If the key doesn't exist, will return null.
* @see #putCache(Uri, Bundle)
+ * {@hide}
*/
+ @SystemApi
public Bundle getCache(Uri key) {
try {
final Bundle bundle = getContentService().getCache(mContext.getPackageName(), key,
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d781a96420c7..a5e7e95f0874 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1790,6 +1790,35 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.action.MANAGE_APP_PERMISSIONS";
/**
+ * Activity action: Launch UI to manage a specific permissions of an app.
+ * <p>
+ * Input: {@link #EXTRA_PACKAGE_NAME} specifies the package whose permission
+ * will be managed by the launched UI.
+ * </p>
+ * <p>
+ * Input: {@link #EXTRA_PERMISSION_NAME} specifies the (individual) permission
+ * that should be managed by the launched UI.
+ * </p>
+ * <p>
+ * <li> {@link #EXTRA_USER} specifies the UserHandle of the user that owns the app.
+ * </p>
+ * <p>
+ * Output: Nothing.
+ * </p>
+ *
+ * @see #EXTRA_PACKAGE_NAME
+ * @see #EXTRA_PERMISSION_NAME
+ * @see #EXTRA_USER
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MANAGE_APP_PERMISSION =
+ "android.intent.action.MANAGE_APP_PERMISSION";
+
+ /**
* Activity action: Launch UI to manage permissions.
* <p>
* Input: Nothing.
@@ -2080,6 +2109,22 @@ public class Intent implements Parcelable, Cloneable {
public static final String ACTION_REVIEW_APP_PERMISSION_USAGE =
"android.intent.action.REVIEW_APP_PERMISSION_USAGE";
+ /**
+ * Activity action: Launch UI to review running accessibility services.
+ * <p>
+ * Input: Nothing.
+ * </p>
+ * <p>
+ * Output: Nothing.
+ * </p>
+ *
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_REVIEW_ACCESSIBILITY_SERVICES =
+ "android.intent.action.REVIEW_ACCESSIBILITY_SERVICES";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent broadcast actions (see action variable).
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 47034a6df8a7..7cc439138527 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1029,10 +1029,18 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
}
/**
+ * Returns true if the activity has maximum or minimum aspect ratio.
+ * @hide
+ */
+ public boolean hasFixedAspectRatio() {
+ return maxAspectRatio != 0 || minAspectRatio != 0;
+ }
+
+ /**
* Returns true if the activity's orientation is fixed.
* @hide
*/
- boolean isFixedOrientation() {
+ public boolean isFixedOrientation() {
return isFixedOrientationLandscape() || isFixedOrientationPortrait()
|| screenOrientation == SCREEN_ORIENTATION_LOCKED;
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index b27c5dc1b457..6c6fcb2ea558 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -650,6 +650,18 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*/
public static final int PRIVATE_FLAG_USE_EMBEDDED_DEX = 1 << 25;
+ /**
+ * Value for {@link #privateFlags}: indicates whether this application's data will be cleared
+ * on a failed restore.
+ *
+ * <p>Comes from the
+ * android.R.styleable#AndroidManifestApplication_allowClearUserDataOnFailedRestore attribute
+ * of the &lt;application&gt; tag.
+ *
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE = 1 << 26;
+
/** @hide */
@IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = {
PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE,
@@ -676,6 +688,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
PRIVATE_FLAG_VENDOR,
PRIVATE_FLAG_VIRTUAL_PRELOAD,
PRIVATE_FLAG_HAS_FRAGILE_USER_DATA,
+ PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApplicationInfoPrivateFlags {}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 0ac4f6481fc4..80954731bffb 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -791,11 +791,6 @@ public class PackageInstaller {
* individual session IDs can be added with {@link #addChildSessionId(int)}
* and commit of the multi-package session will result in all child sessions
* being committed atomically.
- * <p>
- * If a package requires to be installed only at reboot, the session should
- * be marked as a staged session by calling {@link SessionParams#setStaged()}
- * with {@code true}. This can also apply to a multi-package session, in
- * which case all the packages in the session will be applied at reboot.
*/
public static class Session implements Closeable {
/** {@hide} */
@@ -1539,7 +1534,11 @@ public class PackageInstaller {
* Staged sessions are scheduled to be installed at next reboot. Staged sessions can also be
* multi-package. In that case, if any of the children sessions fail to install at reboot,
* all the other children sessions are aborted as well.
+ *
+ * {@hide}
*/
+ @SystemApi
+ @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
public void setStaged() {
this.isStaged = true;
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 6e52b33692c8..3ea78df6ae39 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -715,7 +715,6 @@ public abstract class PackageManager {
INSTALL_FORCE_PERMISSION_PROMPT,
INSTALL_INSTANT_APP,
INSTALL_DONT_KILL_APP,
- INSTALL_FORCE_SDK,
INSTALL_FULL_APP,
INSTALL_ALLOCATE_AGGRESSIVE,
INSTALL_VIRTUAL_PRELOAD,
@@ -816,15 +815,6 @@ public abstract class PackageManager {
public static final int INSTALL_DONT_KILL_APP = 0x00001000;
/**
- * Flag parameter for {@link #installPackage} to indicate that this package is an
- * upgrade to a package that refers to the SDK via release letter or is targeting an SDK via
- * release letter that the current build does not support.
- *
- * @hide
- */
- public static final int INSTALL_FORCE_SDK = 0x00002000;
-
- /**
* Flag parameter for {@link #installPackage} to indicate that this package is
* to be installed as a heavy weight app. This is fundamentally the opposite of
* {@link #INSTALL_INSTANT_APP}.
@@ -5920,24 +5910,24 @@ public abstract class PackageManager {
/**
* Flag to denote no restrictions. This should be used to clear any restrictions that may have
* been previously set for the package.
- * @see PackageManager.DistractionRestriction
* @hide
+ * @see #setDistractingPackageRestrictions(String[], int)
*/
@SystemApi
public static final int RESTRICTION_NONE = 0x0;
/**
* Flag to denote that a package should be hidden from any suggestions to the user.
- * @see PackageManager.DistractionRestriction
* @hide
+ * @see #setDistractingPackageRestrictions(String[], int)
*/
@SystemApi
public static final int RESTRICTION_HIDE_FROM_SUGGESTIONS = 0x00000001;
/**
* Flag to denote that a package's notifications should be hidden.
- * @see PackageManager.DistractionRestriction
* @hide
+ * @see #setDistractingPackageRestrictions(String[], int)
*/
@SystemApi
public static final int RESTRICTION_HIDE_NOTIFICATIONS = 0x00000002;
@@ -5949,7 +5939,6 @@ public abstract class PackageManager {
* @see #setDistractingPackageRestrictions(String[], int)
* @hide
*/
- @SystemApi
@IntDef(flag = true, prefix = {"RESTRICTION_"}, value = {
RESTRICTION_NONE,
RESTRICTION_HIDE_FROM_SUGGESTIONS,
@@ -5967,14 +5956,16 @@ public abstract class PackageManager {
* <p>The caller must hold {@link android.Manifest.permission#SUSPEND_APPS} to use this API.
*
* @param packages Packages to mark as distracting.
- * @param restrictionFlags Any combination of {@link DistractionRestriction restrictions} to
- * impose on the given packages. {@link #RESTRICTION_NONE} can be used
- * to clear any existing restrictions.
+ * @param restrictionFlags Any combination of restrictions to impose on the given packages.
+ * {@link #RESTRICTION_NONE} can be used to clear any existing
+ * restrictions.
* @return A list of packages that could not have the {@code restrictionFlags} set. The system
* may prevent restricting critical packages to preserve normal device function.
*
- * @see DistractionRestriction
* @hide
+ * @see #RESTRICTION_NONE
+ * @see #RESTRICTION_HIDE_FROM_SUGGESTIONS
+ * @see #RESTRICTION_HIDE_NOTIFICATIONS
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.SUSPEND_APPS)
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index cfe35b061151..270e3879a71f 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -163,6 +163,30 @@ public abstract class PackageManagerInternal {
}
/**
+ * Provider for default home
+ */
+ public interface DefaultHomeProvider {
+
+ /**
+ * Get the package name of the default home.
+ *
+ * @param userId the user id
+ *
+ * @return the package name of the default home, or {@code null} if none
+ */
+ @Nullable
+ String getDefaultHome(@UserIdInt int userId);
+
+ /**
+ * Set the package name of the default home.
+ *
+ * @param packageName package name of the default home, or {@code null} to remove
+ * @param userId the user id
+ */
+ void setDefaultHomeAsync(@Nullable String packageName, @UserIdInt int userId);
+ }
+
+ /**
* Sets the location provider packages provider.
* @param provider The packages provider.
*/
@@ -886,4 +910,11 @@ public abstract class PackageManagerInternal {
* @param provider the provider
*/
public abstract void setDefaultBrowserProvider(@NonNull DefaultBrowserProvider provider);
+
+ /**
+ * Sets the default home provider.
+ *
+ * @param provider the provider
+ */
+ public abstract void setDefaultHomeProvider(@NonNull DefaultHomeProvider provider);
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 5020a94c3469..0f67262bf901 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -839,7 +839,6 @@ public class PackageParser {
public static final int PARSE_IS_SYSTEM_DIR = 1 << 4;
public static final int PARSE_COLLECT_CERTIFICATES = 1 << 5;
public static final int PARSE_ENFORCE_CODE = 1 << 6;
- public static final int PARSE_FORCE_SDK = 1 << 7;
public static final int PARSE_CHATTY = 1 << 31;
@IntDef(flag = true, prefix = { "PARSE_" }, value = {
@@ -847,7 +846,6 @@ public class PackageParser {
PARSE_COLLECT_CERTIFICATES,
PARSE_ENFORCE_CODE,
PARSE_EXTERNAL_STORAGE,
- PARSE_FORCE_SDK,
PARSE_IGNORE_PROCESSES,
PARSE_IS_SYSTEM_DIR,
PARSE_MUST_BE_APK,
@@ -2684,8 +2682,6 @@ public class PackageParser {
* @param platformSdkCodenames array of allowed pre-release SDK codenames
* for this platform
* @param outError output array to populate with error, if applicable
- * @param forceCurrentDev if development target code is not available, use the current
- * development version by default.
* @return the targetSdkVersion to use at runtime, or -1 if the package is
* not compatible with this platform
* @hide Exposed for unit testing only.
@@ -2693,7 +2689,7 @@ public class PackageParser {
@TestApi
public static int computeTargetSdkVersion(@IntRange(from = 0) int targetVers,
@Nullable String targetCode, @NonNull String[] platformSdkCodenames,
- @NonNull String[] outError, boolean forceCurrentDev) {
+ @NonNull String[] outError) {
// If it's a release SDK, return the version number unmodified.
if (targetCode == null) {
return targetVers;
@@ -2701,7 +2697,7 @@ public class PackageParser {
// If it's a pre-release SDK and the codename matches this platform, it
// definitely targets this SDK.
- if (matchTargetCode(platformSdkCodenames, targetCode) || forceCurrentDev) {
+ if (matchTargetCode(platformSdkCodenames, targetCode)) {
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
@@ -2768,9 +2764,8 @@ public class PackageParser {
return null;
}
- boolean defaultToCurrentDevBranch = (flags & PARSE_FORCE_SDK) != 0;
final int targetSdkVersion = computeTargetSdkVersion(targetVers,
- targetCode, SDK_CODENAMES, outError, defaultToCurrentDevBranch);
+ targetCode, SDK_CODENAMES, outError);
if (targetSdkVersion < 0) {
return null;
}
@@ -3752,6 +3747,13 @@ public class PackageParser {
ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
}
+ if (sa.getBoolean(
+ com.android.internal.R.styleable
+ .AndroidManifestApplication_allowClearUserDataOnFailedRestore,
+ true)) {
+ ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE;
+ }
+
ai.maxAspectRatio = sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0);
ai.minAspectRatio = sa.getFloat(R.styleable.AndroidManifestApplication_minAspectRatio, 0);
@@ -4846,7 +4848,7 @@ public class PackageParser {
}
/**
- * Sets every the max aspect ratio of every child activity that doesn't already have an aspect
+ * Sets every the min aspect ratio of every child activity that doesn't already have an aspect
* ratio set.
*/
private void setMinAspectRatio(Package owner) {
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index fe68b8a048c2..b1553250d638 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -2273,7 +2273,8 @@ public final class ShortcutInfo implements Parcelable {
CharSequence disabledMessage, int disabledMessageResId, String disabledMessageResName,
Set<String> categories, Intent[] intentsWithExtras, int rank, PersistableBundle extras,
long lastChangedTimestamp,
- int flags, int iconResId, String iconResName, String bitmapPath, int disabledReason) {
+ int flags, int iconResId, String iconResName, String bitmapPath, int disabledReason,
+ Person[] persons) {
mUserId = userId;
mId = id;
mPackageName = packageName;
@@ -2299,5 +2300,6 @@ public final class ShortcutInfo implements Parcelable {
mIconResName = iconResName;
mBitmapPath = bitmapPath;
mDisabledReason = disabledReason;
+ mPersons = persons;
}
}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index faf17e011b23..49b4cb01c6a6 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -47,6 +47,7 @@ import java.nio.channels.FileLock;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.Map;
/**
* Provides access to an application's raw asset files; see {@link Resources}
@@ -1345,6 +1346,17 @@ public final class AssetManager implements AutoCloseable {
}
}
+ /**
+ * @hide
+ */
+ @GuardedBy("this")
+ public @Nullable Map<String, String> getOverlayableMap(String packageName) {
+ synchronized (this) {
+ ensureValidLocked();
+ return nativeGetOverlayableMap(mObject, packageName);
+ }
+ }
+
@GuardedBy("this")
private void incRefsLocked(long id) {
if (DEBUG_REFS) {
@@ -1462,6 +1474,8 @@ public final class AssetManager implements AutoCloseable {
private static native void nativeVerifySystemIdmaps();
private static native String[] nativeCreateIdmapsForStaticOverlaysTargetingAndroid();
+ private static native @Nullable Map nativeGetOverlayableMap(long ptr,
+ @NonNull String packageName);
// Global debug native methods.
/**
diff --git a/core/java/android/debug/AdbManagerInternal.java b/core/java/android/debug/AdbManagerInternal.java
index 4469f0f965c3..51eb7fc2d804 100644
--- a/core/java/android/debug/AdbManagerInternal.java
+++ b/core/java/android/debug/AdbManagerInternal.java
@@ -16,6 +16,8 @@
package android.debug;
+import java.io.File;
+
/**
* This class allows the control of ADB-related functions that should only be called from the system
* server.
@@ -41,4 +43,14 @@ public abstract class AdbManagerInternal {
* Returns {@code true} if ADB debugging is enabled.
*/
public abstract boolean isAdbEnabled();
+
+ /**
+ * Returns the file that contains all of the ADB keys used by the device.
+ */
+ public abstract File getAdbKeysFile();
+
+ /**
+ * Returns the file that contains all of the ADB keys and their last used time.
+ */
+ public abstract File getAdbTempKeysFile();
}
diff --git a/core/java/android/hardware/biometrics/BiometricConstants.java b/core/java/android/hardware/biometrics/BiometricConstants.java
index c814b7c67817..1cb7eb0d1256 100644
--- a/core/java/android/hardware/biometrics/BiometricConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricConstants.java
@@ -17,6 +17,7 @@
package android.hardware.biometrics;
import android.annotation.UnsupportedAppUsage;
+import android.app.KeyguardManager;
/**
@@ -126,6 +127,13 @@ public interface BiometricConstants {
int BIOMETRIC_ERROR_NEGATIVE_BUTTON = 13;
/**
+ * The device does not have pin, pattern, or password set up. See
+ * {@link BiometricPrompt.Builder#setAllowDeviceCredential(boolean)} and
+ * {@link KeyguardManager#isDeviceSecure()}
+ */
+ int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14;
+
+ /**
* @hide
*/
@UnsupportedAppUsage
diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
index b708ef12b210..459ec62d4135 100644
--- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
@@ -16,6 +16,7 @@
package android.hardware.biometrics;
+import android.app.KeyguardManager;
import android.hardware.face.FaceManager;
/**
@@ -134,6 +135,13 @@ public interface BiometricFaceConstants {
public static final int FACE_ERROR_NEGATIVE_BUTTON = 13;
/**
+ * The device does not have pin, pattern, or password set up. See
+ * {@link BiometricPrompt.Builder#setAllowDeviceCredential(boolean)} and
+ * {@link KeyguardManager#isDeviceSecure()}
+ */
+ public static final int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14;
+
+ /**
* @hide
*/
public static final int FACE_ERROR_VENDOR_BASE = 1000;
diff --git a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
index 041b2e673b96..6cbab471ce23 100644
--- a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
@@ -17,6 +17,7 @@
package android.hardware.biometrics;
import android.annotation.UnsupportedAppUsage;
+import android.app.KeyguardManager;
import android.hardware.fingerprint.FingerprintManager;
/**
@@ -119,6 +120,14 @@ public interface BiometricFingerprintConstants {
public static final int FINGERPRINT_ERROR_NEGATIVE_BUTTON = 13;
/**
+ * The device does not have pin, pattern, or password set up. See
+ * {@link BiometricPrompt.Builder#setAllowDeviceCredential(boolean)} and
+ * {@link KeyguardManager#isDeviceSecure()}
+ * @hide
+ */
+ public static final int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14;
+
+ /**
* @hide
*/
@UnsupportedAppUsage
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index d569a7800c37..baf972b26573 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -23,6 +23,7 @@ import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.app.KeyguardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Binder;
@@ -80,7 +81,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
/**
* @hide
*/
- public static final String KEY_ENABLE_FALLBACK = "enable_fallback";
+ public static final String KEY_ALLOW_DEVICE_CREDENTIAL = "allow_device_credential";
/**
* Error/help message will show for this amount of time.
@@ -203,7 +204,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
* "Cancel" button, but may be also used to show an alternative method for authentication,
* such as screen that asks for a backup password.
*
- * Note that this should not be set if {@link #setEnableFallback(boolean)} is set to true.
+ * Note that this should not be set if {@link #setAllowDeviceCredential(boolean)
+ * is set to true.
*
* @param text
* @return
@@ -250,7 +252,10 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
/**
* The user will first be prompted to authenticate with biometrics, but also given the
- * option to authenticate with their device PIN, pattern, or password.
+ * option to authenticate with their device PIN, pattern, or password. Developers should
+ * first check {@link KeyguardManager#isDeviceSecure()} before enabling this. If the device
+ * is not secure, {@link BiometricPrompt#BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL} will be
+ * returned in {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)}}
*
* Note that {@link #setNegativeButton(CharSequence, Executor,
* DialogInterface.OnClickListener)} should not be set if this is set to true.
@@ -259,8 +264,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
* credentials (PIN, pattern, or password).
* @return
*/
- public Builder setEnableFallback(boolean enable) {
- mBundle.putBoolean(KEY_ENABLE_FALLBACK, enable);
+ public Builder setAllowDeviceCredential(boolean enable) {
+ mBundle.putBoolean(KEY_ALLOW_DEVICE_CREDENTIAL, enable);
return this;
}
@@ -273,7 +278,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
final CharSequence title = mBundle.getCharSequence(KEY_TITLE);
final CharSequence negative = mBundle.getCharSequence(KEY_NEGATIVE_TEXT);
final boolean useDefaultTitle = mBundle.getBoolean(KEY_USE_DEFAULT_TITLE);
- final boolean enableFallback = mBundle.getBoolean(KEY_ENABLE_FALLBACK);
+ final boolean enableFallback = mBundle.getBoolean(KEY_ALLOW_DEVICE_CREDENTIAL);
if (TextUtils.isEmpty(title) && !useDefaultTitle) {
throw new IllegalArgumentException("Title must be set and non-empty");
@@ -281,7 +286,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
throw new IllegalArgumentException("Negative text must be set and non-empty");
} else if (!TextUtils.isEmpty(negative) && enableFallback) {
throw new IllegalArgumentException("Can't have both negative button behavior"
- + " and fallback enabled");
+ + " and device credential enabled");
}
return new BiometricPrompt(mContext, mBundle, mPositiveButtonInfo, mNegativeButtonInfo);
}
@@ -541,8 +546,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
if (callback == null) {
throw new IllegalArgumentException("Must supply a callback");
}
- if (mBundle.getBoolean(KEY_ENABLE_FALLBACK)) {
- throw new IllegalArgumentException("Fallback not supported with crypto");
+ if (mBundle.getBoolean(KEY_ALLOW_DEVICE_CREDENTIAL)) {
+ throw new IllegalArgumentException("Device credential not supported with crypto");
}
authenticateInternal(crypto, cancel, executor, callback, mContext.getUserId());
}
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index e4336d171ab6..a20e2bf3d067 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -54,7 +54,7 @@ interface IBiometricService {
// TODO(b/123378871): Remove when moved.
// CDCA needs to send results to BiometricService if it was invoked using BiometricPrompt's
- // setEnableFallback method, since there's no way for us to intercept onActivityResult.
+ // setAllowDeviceCredential method, since there's no way for us to intercept onActivityResult.
// CDCA is launched from BiometricService (startActivityAsUser) instead of *ForResult.
void onConfirmDeviceCredentialSuccess();
// TODO(b/123378871): Remove when moved.
diff --git a/core/java/android/hardware/display/ColorDisplayManager.java b/core/java/android/hardware/display/ColorDisplayManager.java
index 27f0b0425ec3..f413d7cc92af 100644
--- a/core/java/android/hardware/display/ColorDisplayManager.java
+++ b/core/java/android/hardware/display/ColorDisplayManager.java
@@ -365,6 +365,17 @@ public final class ColorDisplayManager {
}
/**
+ * Gets whether or not a non-default saturation level is currently applied to the display.
+ *
+ * @return {@code true} if the display is not at full saturation
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+ public boolean isSaturationActivated() {
+ return mManager.isSaturationActivated();
+ }
+
+ /**
* Set the level of color saturation to apply to a specific app.
*
* @param packageName the package name of the app whose windows should be desaturated
@@ -588,6 +599,14 @@ public final class ColorDisplayManager {
}
}
+ boolean isSaturationActivated() {
+ try {
+ return mCdm.isSaturationActivated();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
boolean setAppSaturationLevel(String packageName, int saturationLevel) {
try {
return mCdm.setAppSaturationLevel(packageName, saturationLevel);
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index f3ebd7f36fd6..ac44fe93ac31 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -16,6 +16,8 @@
package android.hardware.display;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.ParceledListSlice;
@@ -229,7 +231,17 @@ public final class DisplayManagerGlobal {
return getCompatibleDisplay(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
}
- public void registerDisplayListener(DisplayListener listener, Handler handler) {
+ /**
+ * Register a listener for display-related changes.
+ *
+ * @param listener The listener that will be called when display changes occur.
+ * @param handler Handler for the thread that will be receiving the callbacks. May be null.
+ * If null, listener will use the handler for the current thread, and if still null,
+ * the handler for the main thread.
+ * If that is still null, a runtime exception will be thrown.
+ */
+ public void registerDisplayListener(@NonNull DisplayListener listener,
+ @Nullable Handler handler) {
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
@@ -237,7 +249,8 @@ public final class DisplayManagerGlobal {
synchronized (mLock) {
int index = findDisplayListenerLocked(listener);
if (index < 0) {
- mDisplayListeners.add(new DisplayListenerDelegate(listener, handler));
+ Looper looper = getLooperForHandler(handler);
+ mDisplayListeners.add(new DisplayListenerDelegate(listener, looper));
registerCallbackIfNeededLocked();
}
}
@@ -258,6 +271,17 @@ public final class DisplayManagerGlobal {
}
}
+ private static Looper getLooperForHandler(@Nullable Handler handler) {
+ Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
+ if (looper == null) {
+ looper = Looper.getMainLooper();
+ }
+ if (looper == null) {
+ throw new RuntimeException("Could not get Looper for the UI thread.");
+ }
+ return looper;
+ }
+
private int findDisplayListenerLocked(DisplayListener listener) {
final int numListeners = mDisplayListeners.size();
for (int i = 0; i < numListeners; i++) {
@@ -636,8 +660,8 @@ public final class DisplayManagerGlobal {
private static final class DisplayListenerDelegate extends Handler {
public final DisplayListener mListener;
- public DisplayListenerDelegate(DisplayListener listener, Handler handler) {
- super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/);
+ DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper) {
+ super(looper, null, true /*async*/);
mListener = listener;
}
diff --git a/core/java/android/hardware/display/IColorDisplayManager.aidl b/core/java/android/hardware/display/IColorDisplayManager.aidl
index 30e76cfe2787..88b59a6eb8db 100644
--- a/core/java/android/hardware/display/IColorDisplayManager.aidl
+++ b/core/java/android/hardware/display/IColorDisplayManager.aidl
@@ -24,6 +24,7 @@ interface IColorDisplayManager {
boolean setSaturationLevel(int saturationLevel);
boolean setAppSaturationLevel(String packageName, int saturationLevel);
+ boolean isSaturationActivated();
int getTransformCapabilities();
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 2aca55aacf7a..68d36de19963 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -678,11 +678,20 @@ public class ConnectivityManager {
@Deprecated
public static final int TYPE_VPN = 17;
+ /**
+ * A network that is exclusively meant to be used for testing
+ *
+ * @deprecated Use {@link NetworkCapabilities} instead.
+ * @hide
+ */
+ @Deprecated
+ public static final int TYPE_TEST = 18; // TODO: Remove this once NetworkTypes are unused.
+
/** {@hide} */
- public static final int MAX_RADIO_TYPE = TYPE_VPN;
+ public static final int MAX_RADIO_TYPE = TYPE_TEST;
/** {@hide} */
- public static final int MAX_NETWORK_TYPE = TYPE_VPN;
+ public static final int MAX_NETWORK_TYPE = TYPE_TEST;
private static final int MIN_NETWORK_TYPE = TYPE_MOBILE;
diff --git a/core/java/android/net/INetworkMonitorCallbacks.aidl b/core/java/android/net/INetworkMonitorCallbacks.aidl
index a8682f9ddd3b..514658549651 100644
--- a/core/java/android/net/INetworkMonitorCallbacks.aidl
+++ b/core/java/android/net/INetworkMonitorCallbacks.aidl
@@ -24,7 +24,7 @@ oneway interface INetworkMonitorCallbacks {
void onNetworkMonitorCreated(in INetworkMonitor networkMonitor);
void notifyNetworkTested(int testResult, @nullable String redirectUrl);
void notifyPrivateDnsConfigResolved(in PrivateDnsConfigParcel config);
- void showProvisioningNotification(String action);
+ void showProvisioningNotification(String action, String packageName);
void hideProvisioningNotification();
void logCaptivePortalLoginEvent(int eventId, String packageName);
} \ No newline at end of file
diff --git a/core/java/android/net/InterfaceConfiguration.java b/core/java/android/net/InterfaceConfiguration.java
index 62cf7d7ceb25..b9d49c14f6c6 100644
--- a/core/java/android/net/InterfaceConfiguration.java
+++ b/core/java/android/net/InterfaceConfiguration.java
@@ -36,8 +36,9 @@ public class InterfaceConfiguration implements Parcelable {
private LinkAddress mAddr;
private HashSet<String> mFlags = Sets.newHashSet();
- private static final String FLAG_UP = INetd.IF_STATE_UP;
- private static final String FLAG_DOWN = INetd.IF_STATE_DOWN;
+ // Must be kept in sync with constant in INetd.aidl
+ private static final String FLAG_UP = "up";
+ private static final String FLAG_DOWN = "down";
private static final String[] EMPTY_STRING_ARRAY = new String[0];
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 7e9bda14b199..1d2d81dc4fbe 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -597,6 +597,7 @@ public final class NetworkCapabilities implements Parcelable {
TRANSPORT_VPN,
TRANSPORT_WIFI_AWARE,
TRANSPORT_LOWPAN,
+ TRANSPORT_TEST,
})
public @interface Transport { }
@@ -635,10 +636,18 @@ public final class NetworkCapabilities implements Parcelable {
*/
public static final int TRANSPORT_LOWPAN = 6;
+ /**
+ * Indicates this network uses a Test-only virtual interface as a transport.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final int TRANSPORT_TEST = 7;
+
/** @hide */
public static final int MIN_TRANSPORT = TRANSPORT_CELLULAR;
/** @hide */
- public static final int MAX_TRANSPORT = TRANSPORT_LOWPAN;
+ public static final int MAX_TRANSPORT = TRANSPORT_TEST;
/** @hide */
public static boolean isValidTransport(@Transport int transportType) {
@@ -652,7 +661,8 @@ public final class NetworkCapabilities implements Parcelable {
"ETHERNET",
"VPN",
"WIFI_AWARE",
- "LOWPAN"
+ "LOWPAN",
+ "TEST"
};
/**
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 5ab34e9aa6e8..bf272625e713 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -92,16 +92,6 @@ public class NetworkPolicyManager {
public static final int MASK_ALL_NETWORKS = 0b11110000;
public static final int FIREWALL_RULE_DEFAULT = 0;
- public static final int FIREWALL_RULE_ALLOW = INetd.FIREWALL_RULE_ALLOW;
- public static final int FIREWALL_RULE_DENY = INetd.FIREWALL_RULE_DENY;
-
- public static final int FIREWALL_TYPE_WHITELIST = INetd.FIREWALL_WHITELIST;
- public static final int FIREWALL_TYPE_BLACKLIST = INetd.FIREWALL_BLACKLIST;
-
- public static final int FIREWALL_CHAIN_NONE = INetd.FIREWALL_CHAIN_NONE;
- public static final int FIREWALL_CHAIN_DOZABLE = INetd.FIREWALL_CHAIN_DOZABLE;
- public static final int FIREWALL_CHAIN_STANDBY = INetd.FIREWALL_CHAIN_STANDBY;
- public static final int FIREWALL_CHAIN_POWERSAVE = INetd.FIREWALL_CHAIN_POWERSAVE;
public static final String FIREWALL_CHAIN_NAME_NONE = "none";
public static final String FIREWALL_CHAIN_NAME_DOZABLE = "dozable";
diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java
index b6cd6359384a..ca49438390e9 100644
--- a/core/java/android/net/NetworkStack.java
+++ b/core/java/android/net/NetworkStack.java
@@ -15,6 +15,7 @@
*/
package android.net;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
@@ -27,6 +28,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.IDhcpServerCallbacks;
import android.net.ip.IIpClientCallbacks;
@@ -63,9 +65,6 @@ public class NetworkStack {
public static final String PERMISSION_MAINLINE_NETWORK_STACK =
"android.permission.MAINLINE_NETWORK_STACK";
- /** @hide */
- public static final String NETWORKSTACK_PACKAGE_NAME = "com.android.mainline.networkstack";
-
private static final int NETWORKSTACK_TIMEOUT_MS = 10_000;
@NonNull
@@ -204,7 +203,33 @@ public class NetworkStack {
final ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0);
intent.setComponent(comp);
- if (comp == null || !context.bindServiceAsUser(intent, new NetworkStackConnection(),
+ if (comp == null) {
+ Slog.wtf(TAG, "Could not resolve the network stack with " + intent);
+ // TODO: crash/reboot system server ?
+ return;
+ }
+
+ final PackageManager pm = context.getPackageManager();
+ int uid = -1;
+ try {
+ uid = pm.getPackageUid(comp.getPackageName(), UserHandle.USER_SYSTEM);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.wtf("Network stack package not found", e);
+ // Fall through
+ }
+
+ if (uid != Process.NETWORK_STACK_UID) {
+ throw new SecurityException("Invalid network stack UID: " + uid);
+ }
+
+ final int hasPermission =
+ pm.checkPermission(PERMISSION_MAINLINE_NETWORK_STACK, comp.getPackageName());
+ if (hasPermission != PERMISSION_GRANTED) {
+ throw new SecurityException(
+ "Network stack does not have permission " + PERMISSION_MAINLINE_NETWORK_STACK);
+ }
+
+ if (!context.bindServiceAsUser(intent, new NetworkStackConnection(),
Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
Slog.wtf(TAG,
"Could not bind to network stack in-process, or in app with " + intent);
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 1f3369376b10..a851e04e78ec 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -21,13 +21,14 @@ import android.annotation.Nullable;
import android.annotation.WorkerThread;
import java.util.ArrayDeque;
-import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -190,13 +191,19 @@ import java.util.concurrent.atomic.AtomicInteger;
public abstract class AsyncTask<Params, Progress, Result> {
private static final String LOG_TAG = "AsyncTask";
- private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
- // We want at least 2 threads and at most 4 threads in the core pool,
- // preferring to have 1 less than the CPU count to avoid saturating
- // the CPU with background work
- private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
- private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
- private static final int KEEP_ALIVE_SECONDS = 30;
+ // We keep only a single pool thread around all the time.
+ // We let the pool grow to a fairly large number of threads if necessary,
+ // but let them time out quickly. In the unlikely case that we run out of threads,
+ // we fall back to a simple unbounded-queue executor.
+ // This combination ensures that:
+ // 1. We normally keep few threads (1) around.
+ // 2. We queue only after launching a significantly larger, but still bounded, set of threads.
+ // 3. We keep the total number of threads bounded, but still allow an unbounded set
+ // of tasks to be queued.
+ private static final int CORE_POOL_SIZE = 1;
+ private static final int MAXIMUM_POOL_SIZE = 20;
+ private static final int BACKUP_POOL_SIZE = 5;
+ private static final int KEEP_ALIVE_SECONDS = 3;
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
@@ -206,8 +213,29 @@ public abstract class AsyncTask<Params, Progress, Result> {
}
};
- private static final BlockingQueue<Runnable> sPoolWorkQueue =
- new LinkedBlockingQueue<Runnable>(128);
+ // Used only for rejected executions.
+ // Initialization protected by sRunOnSerialPolicy lock.
+ private static ThreadPoolExecutor sBackupExecutor;
+ private static LinkedBlockingQueue<Runnable> sBackupExecutorQueue;
+
+ private static final RejectedExecutionHandler sRunOnSerialPolicy =
+ new RejectedExecutionHandler() {
+ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+ android.util.Log.w(LOG_TAG, "Exceeded ThreadPoolExecutor pool size");
+ // As a last ditch fallback, run it on an executor with an unbounded queue.
+ // Create this executor lazily, hopefully almost never.
+ synchronized (this) {
+ if (sBackupExecutor == null) {
+ sBackupExecutorQueue = new LinkedBlockingQueue<Runnable>();
+ sBackupExecutor = new ThreadPoolExecutor(
+ BACKUP_POOL_SIZE, BACKUP_POOL_SIZE, KEEP_ALIVE_SECONDS,
+ TimeUnit.SECONDS, sBackupExecutorQueue, sThreadFactory);
+ sBackupExecutor.allowCoreThreadTimeOut(true);
+ }
+ }
+ sBackupExecutor.execute(r);
+ }
+ };
/**
* An {@link Executor} that can be used to execute tasks in parallel.
@@ -217,8 +245,8 @@ public abstract class AsyncTask<Params, Progress, Result> {
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
- sPoolWorkQueue, sThreadFactory);
- threadPoolExecutor.allowCoreThreadTimeOut(true);
+ new SynchronousQueue<Runnable>(), sThreadFactory);
+ threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index ab6dd7c07b42..b7e65b9151b9 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -46,6 +46,7 @@ import com.android.internal.os.BatteryStatsHelper;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -262,6 +263,7 @@ public abstract class BatteryStats implements Parcelable {
private static final long BYTES_PER_KB = 1024;
private static final long BYTES_PER_MB = 1048576; // 1024^2
private static final long BYTES_PER_GB = 1073741824; //1024^3
+ public static final double MILLISECONDS_IN_HOUR = 3600 * 1000;
private static final String VERSION_DATA = "vers";
private static final String UID_DATA = "uid";
@@ -482,6 +484,13 @@ public abstract class BatteryStats implements Parcelable {
* yield a value of 0 if the device doesn't support power calculations.
*/
public abstract LongCounter getPowerCounter();
+
+ /**
+ * @return a non-null {@link LongCounter} representing total power monitored on the rails
+ * in mAms (miliamps-milliseconds). The counter may always yield a value of 0 if the device
+ * doesn't support power rail monitoring.
+ */
+ public abstract LongCounter getMonitoredRailChargeConsumedMaMs();
}
/**
@@ -1526,6 +1535,9 @@ public abstract class BatteryStats implements Parcelable {
// The charge of the battery in micro-Ampere-hours.
public int batteryChargeUAh;
+ public double modemRailChargeMah;
+ public double wifiRailChargeMah;
+
// Constants from SCREEN_BRIGHTNESS_*
public static final int STATE_BRIGHTNESS_SHIFT = 0;
public static final int STATE_BRIGHTNESS_MASK = 0x7;
@@ -1738,6 +1750,8 @@ public abstract class BatteryStats implements Parcelable {
| ((((int)batteryVoltage)<<16)&0xffff0000);
dest.writeInt(bat);
dest.writeInt(batteryChargeUAh);
+ dest.writeDouble(modemRailChargeMah);
+ dest.writeDouble(wifiRailChargeMah);
dest.writeInt(states);
dest.writeInt(states2);
if (wakelockTag != null) {
@@ -1767,6 +1781,8 @@ public abstract class BatteryStats implements Parcelable {
batteryTemperature = (short)(bat2&0xffff);
batteryVoltage = (char)((bat2>>16)&0xffff);
batteryChargeUAh = src.readInt();
+ modemRailChargeMah = src.readDouble();
+ wifiRailChargeMah = src.readDouble();
states = src.readInt();
states2 = src.readInt();
if ((bat&0x10000000) != 0) {
@@ -1807,6 +1823,8 @@ public abstract class BatteryStats implements Parcelable {
batteryTemperature = 0;
batteryVoltage = 0;
batteryChargeUAh = 0;
+ modemRailChargeMah = 0;
+ wifiRailChargeMah = 0;
states = 0;
states2 = 0;
wakelockTag = null;
@@ -1835,6 +1853,8 @@ public abstract class BatteryStats implements Parcelable {
batteryTemperature = o.batteryTemperature;
batteryVoltage = o.batteryVoltage;
batteryChargeUAh = o.batteryChargeUAh;
+ modemRailChargeMah = o.modemRailChargeMah;
+ wifiRailChargeMah = o.wifiRailChargeMah;
states = o.states;
states2 = o.states2;
if (o.wakelockTag != null) {
@@ -1867,6 +1887,8 @@ public abstract class BatteryStats implements Parcelable {
&& batteryTemperature == o.batteryTemperature
&& batteryVoltage == o.batteryVoltage
&& batteryChargeUAh == o.batteryChargeUAh
+ && modemRailChargeMah == o.modemRailChargeMah
+ && wifiRailChargeMah == o.wifiRailChargeMah
&& states == o.states
&& states2 == o.states2
&& currentTime == o.currentTime;
@@ -3311,7 +3333,8 @@ public abstract class BatteryStats implements Parcelable {
if (counter.getIdleTimeCounter().getCountLocked(which) != 0
|| counter.getRxTimeCounter().getCountLocked(which) != 0
- || counter.getPowerCounter().getCountLocked(which) != 0) {
+ || counter.getPowerCounter().getCountLocked(which) != 0
+ || counter.getMonitoredRailChargeConsumedMaMs().getCountLocked(which) != 0) {
return true;
}
@@ -3345,7 +3368,10 @@ public abstract class BatteryStats implements Parcelable {
pw.print(",");
pw.print(counter.getRxTimeCounter().getCountLocked(which));
pw.print(",");
- pw.print(counter.getPowerCounter().getCountLocked(which) / (1000 * 60 * 60));
+ pw.print(counter.getPowerCounter().getCountLocked(which) / (MILLISECONDS_IN_HOUR));
+ pw.print(",");
+ pw.print(counter.getMonitoredRailChargeConsumedMaMs().getCountLocked(which)
+ / (MILLISECONDS_IN_HOUR));
for (LongCounter c : counter.getTxTimeCounters()) {
pw.print(",");
pw.print(c.getCountLocked(which));
@@ -3370,7 +3396,10 @@ public abstract class BatteryStats implements Parcelable {
proto.write(ControllerActivityProto.RX_DURATION_MS,
counter.getRxTimeCounter().getCountLocked(which));
proto.write(ControllerActivityProto.POWER_MAH,
- counter.getPowerCounter().getCountLocked(which) / (1000 * 60 * 60));
+ counter.getPowerCounter().getCountLocked(which) / (MILLISECONDS_IN_HOUR));
+ proto.write(ControllerActivityProto.MONITORED_RAIL_CHARGE_MAH,
+ counter.getMonitoredRailChargeConsumedMaMs().getCountLocked(which)
+ / (MILLISECONDS_IN_HOUR));
long tToken;
LongCounter[] txCounters = counter.getTxTimeCounters();
@@ -3400,6 +3429,8 @@ public abstract class BatteryStats implements Parcelable {
final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(which);
final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(which);
final long powerDrainMaMs = counter.getPowerCounter().getCountLocked(which);
+ final long monitoredRailChargeConsumedMaMs =
+ counter.getMonitoredRailChargeConsumedMaMs().getCountLocked(which);
// Battery real time
final long totalControllerActivityTimeMs
= computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which) / 1000;
@@ -3522,10 +3553,22 @@ public abstract class BatteryStats implements Parcelable {
sb.append(" ");
sb.append(controllerName);
sb.append(" Battery drain: ").append(
- BatteryStatsHelper.makemAh(powerDrainMaMs / (double) (1000*60*60)));
+ BatteryStatsHelper.makemAh(powerDrainMaMs / MILLISECONDS_IN_HOUR));
sb.append("mAh");
pw.println(sb.toString());
}
+
+ if (monitoredRailChargeConsumedMaMs > 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" ");
+ sb.append(controllerName);
+ sb.append(" Monitored rail energy drain: ").append(
+ new DecimalFormat("#.##").format(
+ monitoredRailChargeConsumedMaMs / MILLISECONDS_IN_HOUR));
+ sb.append(" mAh");
+ pw.println(sb.toString());
+ }
}
/**
@@ -6103,6 +6146,8 @@ public abstract class BatteryStats implements Parcelable {
int oldTemp = -1;
int oldVolt = -1;
int oldChargeMAh = -1;
+ double oldModemRailChargeMah = -1;
+ double oldWifiRailChargeMah = -1;
long lastTime = -1;
void reset() {
@@ -6114,6 +6159,8 @@ public abstract class BatteryStats implements Parcelable {
oldTemp = -1;
oldVolt = -1;
oldChargeMAh = -1;
+ oldModemRailChargeMah = -1;
+ oldWifiRailChargeMah = -1;
}
public void printNextItem(PrintWriter pw, HistoryItem rec, long baseTime, boolean checkin,
@@ -6299,6 +6346,16 @@ public abstract class BatteryStats implements Parcelable {
item.append(checkin ? ",Bcc=" : " charge=");
item.append(oldChargeMAh);
}
+ if (oldModemRailChargeMah != rec.modemRailChargeMah) {
+ oldModemRailChargeMah = rec.modemRailChargeMah;
+ item.append(checkin ? ",Mrc=" : " modemRailChargemAh=");
+ item.append(new DecimalFormat("#.##").format(oldModemRailChargeMah));
+ }
+ if (oldWifiRailChargeMah != rec.wifiRailChargeMah) {
+ oldWifiRailChargeMah = rec.wifiRailChargeMah;
+ item.append(checkin ? ",Wrc=" : " wifiRailChargemAh=");
+ item.append(new DecimalFormat("#.##").format(oldWifiRailChargeMah));
+ }
printBitDescriptions(item, oldState, rec.states, rec.wakelockTag,
HISTORY_STATE_DESCRIPTIONS, !checkin);
printBitDescriptions(item, oldState2, rec.states2, null,
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 629289bb7a45..0384faa88be5 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -1093,6 +1093,12 @@ public class FileUtils {
return buildUniqueFileWithExtension(parent, parts[0], parts[1]);
}
+ /** {@hide} */
+ public static File buildNonUniqueFile(File parent, String mimeType, String displayName) {
+ final String[] parts = splitFileName(mimeType, displayName);
+ return buildFile(parent, parts[0], parts[1]);
+ }
+
/**
* Generates a unique file name under the given parent directory, keeping
* any extension intact.
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 269c781397ad..cc241b3b7756 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -16,6 +16,7 @@
package android.os;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -24,14 +25,10 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
-import android.gamedriver.GameDriverProto.Blacklist;
-import android.gamedriver.GameDriverProto.Blacklists;
import android.opengl.EGL14;
import android.provider.Settings;
-import android.util.Base64;
import android.util.Log;
-
-import com.android.framework.protobuf.InvalidProtocolBufferException;
+import android.widget.Toast;
import dalvik.system.VMRuntime;
@@ -67,8 +64,7 @@ public class GraphicsEnvironment {
private static final String ANGLE_RULES_FILE = "a4a_rules.json";
private static final String ANGLE_TEMP_RULES = "debug.angle.rules";
private static final String ACTION_ANGLE_FOR_ANDROID = "android.app.action.ANGLE_FOR_ANDROID";
- private static final String GAME_DRIVER_BLACKLIST_FLAG = "blacklist";
- private static final int BASE64_FLAGS = Base64.NO_PADDING | Base64.NO_WRAP;
+ private static final String GAME_DRIVER_WHITELIST_ALL = "*";
private ClassLoader mClassLoader;
private String mLayerPath;
@@ -222,9 +218,17 @@ public class GraphicsEnvironment {
}
- private static List<String> getGlobalSettingsString(Bundle bundle, String globalSetting) {
- List<String> valueList = null;
- final String settingsValue = bundle.getString(globalSetting);
+ private static List<String> getGlobalSettingsString(ContentResolver contentResolver,
+ Bundle bundle,
+ String globalSetting) {
+ final List<String> valueList;
+ final String settingsValue;
+
+ if (bundle != null) {
+ settingsValue = bundle.getString(globalSetting);
+ } else {
+ settingsValue = Settings.Global.getString(contentResolver, globalSetting);
+ }
if (settingsValue != null) {
valueList = new ArrayList<>(Arrays.asList(settingsValue.split(",")));
@@ -246,17 +250,27 @@ public class GraphicsEnvironment {
return -1;
}
- private static String getDriverForPkg(Bundle bundle, String packageName) {
- final String allUseAngle =
- bundle.getString(Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE);
+ private static String getDriverForPkg(Context context, Bundle bundle, String packageName) {
+ final String allUseAngle;
+ if (bundle != null) {
+ allUseAngle =
+ bundle.getString(Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE);
+ } else {
+ ContentResolver contentResolver = context.getContentResolver();
+ allUseAngle = Settings.Global.getString(contentResolver,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE);
+ }
if ((allUseAngle != null) && allUseAngle.equals("1")) {
return sDriverMap.get(OpenGlDriverChoice.ANGLE);
}
- final List<String> globalSettingsDriverPkgs = getGlobalSettingsString(
- bundle, Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS);
- final List<String> globalSettingsDriverValues = getGlobalSettingsString(
- bundle, Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES);
+ final ContentResolver contentResolver = context.getContentResolver();
+ final List<String> globalSettingsDriverPkgs =
+ getGlobalSettingsString(contentResolver, bundle,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS);
+ final List<String> globalSettingsDriverValues =
+ getGlobalSettingsString(contentResolver, bundle,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES);
// Make sure we have a good package name
if ((packageName == null) || (packageName.isEmpty())) {
@@ -308,7 +322,7 @@ public class GraphicsEnvironment {
* True: Temporary rules file was loaded.
* False: Temporary rules file was *not* loaded.
*/
- private boolean setupAngleWithTempRulesFile(Context context,
+ private static boolean setupAngleWithTempRulesFile(Context context,
String packageName,
String paths,
String devOptIn) {
@@ -372,7 +386,7 @@ public class GraphicsEnvironment {
* True: APK rules file was loaded.
* False: APK rules file was *not* loaded.
*/
- private boolean setupAngleRulesApk(String anglePkgName,
+ private static boolean setupAngleRulesApk(String anglePkgName,
ApplicationInfo angleInfo,
PackageManager pm,
String packageName,
@@ -405,23 +419,32 @@ public class GraphicsEnvironment {
/**
* Pull ANGLE whitelist from GlobalSettings and compare against current package
*/
- private boolean checkAngleWhitelist(Bundle bundle, String packageName) {
+ private static boolean checkAngleWhitelist(Context context, Bundle bundle, String packageName) {
+ final ContentResolver contentResolver = context.getContentResolver();
final List<String> angleWhitelist =
- getGlobalSettingsString(bundle, Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST);
+ getGlobalSettingsString(contentResolver, bundle,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST);
return angleWhitelist.contains(packageName);
}
/**
* Pass ANGLE details down to trigger enable logic
+ *
+ * @param context
+ * @param bundle
+ * @param packageName
+ * @return true: ANGLE setup successfully
+ * false: ANGLE not setup (not on whitelist, ANGLE not present, etc.)
*/
- public void setupAngle(Context context, Bundle bundle, PackageManager pm, String packageName) {
+ public boolean setupAngle(Context context, Bundle bundle, PackageManager pm,
+ String packageName) {
if (packageName.isEmpty()) {
Log.v(TAG, "No package name available yet, skipping ANGLE setup");
- return;
+ return false;
}
- final String devOptIn = getDriverForPkg(bundle, packageName);
+ final String devOptIn = getDriverForPkg(context, bundle, packageName);
if (DEBUG) {
Log.v(TAG, "ANGLE Developer option for '" + packageName + "' "
+ "set to: '" + devOptIn + "'");
@@ -439,11 +462,11 @@ public class GraphicsEnvironment {
// load a driver, GraphicsEnv::shouldUseAngle() has seen the package name before
// and can confidently answer yes/no based on the previously set developer
// option value.
- final boolean whitelisted = checkAngleWhitelist(bundle, packageName);
+ final boolean whitelisted = checkAngleWhitelist(context, bundle, packageName);
final boolean defaulted = devOptIn.equals(sDriverMap.get(OpenGlDriverChoice.DEFAULT));
final boolean rulesCheck = (whitelisted || !defaulted);
if (!rulesCheck) {
- return;
+ return false;
}
if (whitelisted) {
@@ -456,7 +479,7 @@ public class GraphicsEnvironment {
final String anglePkgName = getAnglePackageName(pm);
if (anglePkgName.isEmpty()) {
Log.e(TAG, "Failed to find ANGLE package.");
- return;
+ return false;
}
final ApplicationInfo angleInfo;
@@ -464,7 +487,7 @@ public class GraphicsEnvironment {
angleInfo = pm.getApplicationInfo(anglePkgName, PackageManager.MATCH_SYSTEM_ONLY);
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "ANGLE package '" + anglePkgName + "' not installed");
- return;
+ return false;
}
final String abi = chooseAbi(angleInfo);
@@ -480,12 +503,62 @@ public class GraphicsEnvironment {
if (setupAngleWithTempRulesFile(context, packageName, paths, devOptIn)) {
// We setup ANGLE with a temp rules file, so we're done here.
- return;
+ return true;
}
if (setupAngleRulesApk(anglePkgName, angleInfo, pm, packageName, paths, devOptIn)) {
// We setup ANGLE with rules from the APK, so we're done here.
- return;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Determine if the "ANGLE In Use" dialog box should be shown.
+ */
+ private boolean shouldShowAngleInUseDialogBox(Context context) {
+ try {
+ ContentResolver contentResolver = context.getContentResolver();
+ final int showDialogBox = Settings.Global.getInt(contentResolver,
+ Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX);
+
+ return (showDialogBox == 1);
+ } catch (Settings.SettingNotFoundException | SecurityException e) {
+ // Do nothing and move on
+ }
+
+ // No setting, so assume false
+ return false;
+ }
+
+ /**
+ * Determine if ANGLE should be used.
+ */
+ private boolean shouldUseAngle(Context context, String packageName) {
+ // Need to make sure we are evaluating ANGLE usage for the correct circumstances
+ if (!setupAngle(context, null, context.getPackageManager(), packageName)) {
+ Log.v(TAG, "Package '" + packageName + "' should use not ANGLE");
+ return false;
+ }
+
+ final boolean useAngle = getShouldUseAngle(packageName);
+ Log.v(TAG, "Package '" + packageName + "' should use ANGLE = '" + useAngle + "'");
+
+ return useAngle;
+ }
+
+ /**
+ * Show the ANGLE in Use Dialog Box
+ * @param context
+ */
+ public void showAngleInUseDialogBox(Context context) {
+ final String packageName = context.getPackageName();
+
+ if (shouldShowAngleInUseDialogBox(context) && shouldUseAngle(context, packageName)) {
+ final String toastMsg = packageName + " is using ANGLE";
+ final Toast toast = Toast.makeText(context, toastMsg, Toast.LENGTH_LONG);
+ toast.show();
}
}
@@ -541,53 +614,33 @@ public class GraphicsEnvironment {
if (gameDriverAllApps != 1) {
// GAME_DRIVER_OPT_OUT_APPS has higher priority than GAME_DRIVER_OPT_IN_APPS
- if (getGlobalSettingsString(coreSettings, Settings.Global.GAME_DRIVER_OPT_OUT_APPS)
- .contains(packageName)) {
+ if (getGlobalSettingsString(null, coreSettings,
+ Settings.Global.GAME_DRIVER_OPT_OUT_APPS).contains(packageName)) {
if (DEBUG) {
Log.w(TAG, packageName + " opts out from Game Driver.");
}
return false;
}
final boolean isOptIn =
- getGlobalSettingsString(coreSettings, Settings.Global.GAME_DRIVER_OPT_IN_APPS)
- .contains(packageName);
- if (!isOptIn
- && !getGlobalSettingsString(coreSettings, Settings.Global.GAME_DRIVER_WHITELIST)
- .contains(packageName)) {
+ getGlobalSettingsString(null, coreSettings,
+ Settings.Global.GAME_DRIVER_OPT_IN_APPS).contains(packageName);
+ final List<String> whitelist = getGlobalSettingsString(null, coreSettings,
+ Settings.Global.GAME_DRIVER_WHITELIST);
+ if (!isOptIn && whitelist.indexOf(GAME_DRIVER_WHITELIST_ALL) != 0
+ && !whitelist.contains(packageName)) {
if (DEBUG) {
Log.w(TAG, packageName + " is not on the whitelist.");
}
return false;
}
- if (!isOptIn) {
- // At this point, the application is on the whitelist only, check whether it's
- // on the blacklist, terminate early when it's on the blacklist.
- try {
- // TODO(b/121350991) Switch to DeviceConfig with property listener.
- final String base64String =
- coreSettings.getString(Settings.Global.GAME_DRIVER_BLACKLIST);
- if (base64String != null && !base64String.isEmpty()) {
- final Blacklists blacklistsProto =
- Blacklists.parseFrom(Base64.decode(base64String, BASE64_FLAGS));
- final List<Blacklist> blacklists = blacklistsProto.getBlacklistsList();
- final long driverVersionCode = driverAppInfo.longVersionCode;
- for (Blacklist blacklist : blacklists) {
- if (blacklist.getVersionCode() == driverVersionCode) {
- for (String pkgName : blacklist.getPackageNamesList()) {
- if (pkgName == packageName) {
- return false;
- }
- }
- break;
- }
- }
- }
- } catch (InvalidProtocolBufferException e) {
- if (DEBUG) {
- Log.w(TAG, "Can't parse blacklist, skip and continue...");
- }
- }
+ // If the application is not opted-in and check whether it's on the blacklist,
+ // terminate early if it's on the blacklist and fallback to system driver.
+ if (!isOptIn
+ && getGlobalSettingsString(null, coreSettings,
+ Settings.Global.GAME_DRIVER_BLACKLIST)
+ .contains(ai.packageName)) {
+ return false;
}
}
@@ -660,4 +713,5 @@ public class GraphicsEnvironment {
long driverVersionCode, String appPackageName);
private static native void setAngleInfo(String path, String appPackage, String devOptIn,
FileDescriptor rulesFd, long rulesOffset, long rulesLength);
+ private static native boolean getShouldUseAngle(String packageName);
}
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index dde46cd93d5f..0751b964f85e 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -69,6 +69,12 @@ interface IStatsCompanionService {
oneway void sendDataBroadcast(in IBinder intentSender, long lastReportTimeNs);
/**
+ * Send a broadcast to the specified PendingIntent's as IBinder notifying it that the list
+ * of active configs has changed.
+ */
+ oneway void sendActiveConfigsChangedBroadcast(in IBinder intentSender, in long[] configIds);
+
+ /**
* Requests StatsCompanionService to send a broadcast using the given intentSender
* (which should cast to an IIntentSender), along with the other information specified.
*/
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
index 93d6f4c12128..6d4c5a034b54 100644
--- a/core/java/android/os/IStatsManager.aidl
+++ b/core/java/android/os/IStatsManager.aidl
@@ -16,6 +16,8 @@
package android.os;
+import android.os.IStatsPullerCallback;
+
/**
* Binder interface to communicate with the statistics management service.
* {@hide}
@@ -178,4 +180,41 @@ interface IStatsManager {
* this label. This allows building custom metrics and predicates.
*/
void sendAppBreadcrumbAtom(int label, int state);
+
+ /**
+ * Registers a puller callback function that, when invoked, pulls the data
+ * for the specified vendor atom tag.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS
+ */
+ oneway void registerPullerCallback(int atomTag, IStatsPullerCallback pullerCallback,
+ String packageName);
+
+ /**
+ * Unregisters a puller callback function for the given vendor atom.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS
+ */
+ oneway void unregisterPullerCallback(int atomTag, String packageName);
+
+ /**
+ * The install requires staging.
+ */
+ const int FLAG_REQUIRE_STAGING = 0x01;
+
+ /**
+ * Rollback is enabled with this install.
+ */
+ const int FLAG_ROLLBACK_ENABLED = 0x02;
+
+ /**
+ * Requires low latency monitoring.
+ */
+ const int FLAG_REQUIRE_LOW_LATENCY_MONITOR = 0x04;
+
+ /**
+ * Logs an event for binary push for module updates.
+ */
+ oneway void sendBinaryPushStateChangedAtom(in String trainName, in long trainVersionCode,
+ in int options, in int state, in long[] experimentId);
}
diff --git a/core/java/android/os/IStatsPullerCallback.aidl b/core/java/android/os/IStatsPullerCallback.aidl
new file mode 100644
index 000000000000..1684aeb0d666
--- /dev/null
+++ b/core/java/android/os/IStatsPullerCallback.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.os.StatsLogEventWrapper;
+
+/**
+ * Binder interface to pull atoms for the stats service.
+ * {@hide}
+ */
+interface IStatsPullerCallback {
+ /**
+ * Pull data for the specified atom tag. Returns an array of StatsLogEventWrapper containing
+ * the data.
+ *
+ * Note: These pulled atoms should not have uid/attribution chain. Additionally, the event
+ * timestamps will be truncated to the nearest 5 minutes.
+ */
+ StatsLogEventWrapper[] pullData(int atomTag, long elapsedNanos, long wallClocknanos);
+
+}
diff --git a/core/java/android/os/LocaleList.java b/core/java/android/os/LocaleList.java
index 87e1b7d21f53..1420e2f5ce10 100644
--- a/core/java/android/os/LocaleList.java
+++ b/core/java/android/os/LocaleList.java
@@ -20,6 +20,7 @@ import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Size;
+import android.annotation.SystemApi;
import android.content.LocaleProto;
import android.icu.util.ULocale;
import android.util.proto.ProtoOutputStream;
@@ -324,6 +325,15 @@ public final class LocaleList implements Parcelable {
return LOCALE_EN_XA.equals(locale) || LOCALE_AR_XB.equals(locale);
}
+ /**
+ * Returns true if locale is a pseudo-locale, false otherwise.
+ * {@hide}
+ */
+ @SystemApi
+ public static boolean isPseudoLocale(@Nullable ULocale locale) {
+ return isPseudoLocale(locale != null ? locale.toLocale() : null);
+ }
+
@IntRange(from=0, to=1)
private static int matchScore(Locale supported, Locale desired) {
if (supported.equals(desired)) {
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 2ecf9d1159f0..cfe2d28f1024 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -1784,7 +1784,7 @@ public final class PowerManager {
*
* see {@link #registerThermalStatusCallback}
*/
- public void unregisterThermalStatusCallback(ThermalStatusCallback callback) {
+ public void unregisterThermalStatusCallback(@NonNull ThermalStatusCallback callback) {
Preconditions.checkNotNull(callback, "callback cannnot be null");
synchronized (this) {
if (mThermalService == null) {
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 8492b0cf58e2..3ee54ceebaa9 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -32,6 +32,7 @@ import android.content.pm.PackageManager;
import android.provider.Settings;
import android.telephony.euicc.EuiccManager;
import android.text.TextUtils;
+import android.text.format.DateFormat;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
@@ -762,7 +763,8 @@ public class RecoverySystem {
String reasonArg = null;
if (!TextUtils.isEmpty(reason)) {
- reasonArg = "--reason=" + sanitizeArg(reason);
+ String timeStamp = DateFormat.format("yyyy-MM-ddTHH:mm:ssZ", System.currentTimeMillis()).toString();
+ reasonArg = "--reason=" + sanitizeArg(reason + "," + timeStamp);
}
final String localeArg = "--locale=" + Locale.getDefault().toLanguageTag() ;
diff --git a/core/java/android/os/StatsLogEventWrapper.java b/core/java/android/os/StatsLogEventWrapper.java
index acb9eac3572c..23342426693a 100644
--- a/core/java/android/os/StatsLogEventWrapper.java
+++ b/core/java/android/os/StatsLogEventWrapper.java
@@ -57,20 +57,18 @@ public final class StatsLogEventWrapper implements Parcelable {
public static final Parcelable.Creator<StatsLogEventWrapper> CREATOR = new
Parcelable.Creator<StatsLogEventWrapper>() {
public StatsLogEventWrapper createFromParcel(Parcel in) {
- android.util.EventLog.writeEvent(0x534e4554, "112550251",
- android.os.Binder.getCallingUid(), "");
- // Purposefully leaving this method not implemented.
- throw new RuntimeException("Not implemented");
+ return new StatsLogEventWrapper(in);
}
public StatsLogEventWrapper[] newArray(int size) {
- android.util.EventLog.writeEvent(0x534e4554, "112550251",
- android.os.Binder.getCallingUid(), "");
- // Purposefully leaving this method not implemented.
- throw new RuntimeException("Not implemented");
+ return new StatsLogEventWrapper[size];
}
};
+ private StatsLogEventWrapper(Parcel in) {
+ readFromParcel(in);
+ }
+
/**
* Set work source if any.
*/
@@ -197,6 +195,70 @@ public final class StatsLogEventWrapper implements Parcelable {
}
/**
+ * Reads from parcel and appropriately fills member fields.
+ */
+ public void readFromParcel(Parcel in) {
+ mTypes = new ArrayList<>();
+ mValues = new ArrayList<>();
+ mWorkSource = null;
+
+ mTag = in.readInt();
+ mElapsedTimeNs = in.readLong();
+ mWallClockTimeNs = in.readLong();
+
+ // Clear any data.
+ if (DEBUG) {
+ Slog.d(TAG, "Reading " + mTag + " " + mElapsedTimeNs + " " + mWallClockTimeNs);
+ }
+ // Set up worksource if present.
+ int numWorkChains = in.readInt();
+ if (numWorkChains > 0) {
+ mWorkSource = new WorkSource();
+ for (int i = 0; i < numWorkChains; i++) {
+ android.os.WorkSource.WorkChain workChain = mWorkSource.createWorkChain();
+ int workChainSize = in.readInt();
+ for (int j = 0; j < workChainSize; j++) {
+ int uid = in.readInt();
+ String tag = in.readString();
+ workChain.addNode(uid, tag);
+ }
+ }
+ }
+
+ // Do the rest of the types.
+ int numTypes = in.readInt();
+ if (DEBUG) {
+ Slog.d(TAG, "Reading " + numTypes + " elements");
+ }
+ for (int i = 0; i < numTypes; i++) {
+ int type = in.readInt();
+ mTypes.add(type);
+ switch (type) {
+ case EVENT_TYPE_INT:
+ mValues.add(in.readInt());
+ break;
+ case EVENT_TYPE_LONG:
+ mValues.add(in.readLong());
+ break;
+ case EVENT_TYPE_FLOAT:
+ mValues.add(in.readFloat());
+ break;
+ case EVENT_TYPE_DOUBLE:
+ mValues.add(in.readDouble());
+ break;
+ case EVENT_TYPE_STRING:
+ mValues.add(in.readString());
+ break;
+ case EVENT_TYPE_STORAGE:
+ mValues.add(in.createByteArray());
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /**
* Boilerplate for Parcel.
*/
public int describeContents() {
diff --git a/core/java/android/os/connectivity/CellularBatteryStats.java b/core/java/android/os/connectivity/CellularBatteryStats.java
index 2593c85cff12..c99ecb32d418 100644
--- a/core/java/android/os/connectivity/CellularBatteryStats.java
+++ b/core/java/android/os/connectivity/CellularBatteryStats.java
@@ -44,6 +44,7 @@ public final class CellularBatteryStats implements Parcelable {
private long[] mTimeInRatMs;
private long[] mTimeInRxSignalStrengthLevelMs;
private long[] mTxTimeMs;
+ private long mMonitoredRailChargeConsumedMaMs;
public static final Parcelable.Creator<CellularBatteryStats> CREATOR = new
Parcelable.Creator<CellularBatteryStats>() {
@@ -74,6 +75,7 @@ public final class CellularBatteryStats implements Parcelable {
out.writeLongArray(mTimeInRatMs);
out.writeLongArray(mTimeInRxSignalStrengthLevelMs);
out.writeLongArray(mTxTimeMs);
+ out.writeLong(mMonitoredRailChargeConsumedMaMs);
}
public void readFromParcel(Parcel in) {
@@ -90,6 +92,7 @@ public final class CellularBatteryStats implements Parcelable {
in.readLongArray(mTimeInRatMs);
in.readLongArray(mTimeInRxSignalStrengthLevelMs);
in.readLongArray(mTxTimeMs);
+ mMonitoredRailChargeConsumedMaMs = in.readLong();
}
public long getLoggingDurationMs() {
@@ -144,6 +147,10 @@ public final class CellularBatteryStats implements Parcelable {
return mTxTimeMs;
}
+ public long getMonitoredRailChargeConsumedMaMs() {
+ return mMonitoredRailChargeConsumedMaMs;
+ }
+
public void setLoggingDurationMs(long t) {
mLoggingDurationMs = t;
return;
@@ -211,6 +218,11 @@ public final class CellularBatteryStats implements Parcelable {
return;
}
+ public void setMonitoredRailChargeConsumedMaMs(long monitoredRailEnergyConsumedMaMs) {
+ mMonitoredRailChargeConsumedMaMs = monitoredRailEnergyConsumedMaMs;
+ return;
+ }
+
public int describeContents() {
return 0;
}
@@ -237,6 +249,7 @@ public final class CellularBatteryStats implements Parcelable {
Arrays.fill(mTimeInRxSignalStrengthLevelMs, 0);
mTxTimeMs = new long[ModemActivityInfo.TX_POWER_LEVELS];
Arrays.fill(mTxTimeMs, 0);
+ mMonitoredRailChargeConsumedMaMs = 0;
return;
}
} \ No newline at end of file
diff --git a/core/java/android/os/connectivity/WifiBatteryStats.java b/core/java/android/os/connectivity/WifiBatteryStats.java
index e5341eeeb17b..3639c71ae3b5 100644
--- a/core/java/android/os/connectivity/WifiBatteryStats.java
+++ b/core/java/android/os/connectivity/WifiBatteryStats.java
@@ -44,6 +44,7 @@ public final class WifiBatteryStats implements Parcelable {
private long[] mTimeInStateMs;
private long[] mTimeInSupplicantStateMs;
private long[] mTimeInRxSignalStrengthLevelMs;
+ private long mMonitoredRailChargeConsumedMaMs;
public static final Parcelable.Creator<WifiBatteryStats> CREATOR = new
Parcelable.Creator<WifiBatteryStats>() {
@@ -77,6 +78,7 @@ public final class WifiBatteryStats implements Parcelable {
out.writeLongArray(mTimeInStateMs);
out.writeLongArray(mTimeInRxSignalStrengthLevelMs);
out.writeLongArray(mTimeInSupplicantStateMs);
+ out.writeLong(mMonitoredRailChargeConsumedMaMs);
}
public void readFromParcel(Parcel in) {
@@ -96,6 +98,7 @@ public final class WifiBatteryStats implements Parcelable {
in.readLongArray(mTimeInStateMs);
in.readLongArray(mTimeInRxSignalStrengthLevelMs);
in.readLongArray(mTimeInSupplicantStateMs);
+ mMonitoredRailChargeConsumedMaMs = in.readLong();
}
public long getLoggingDurationMs() {
@@ -162,6 +165,10 @@ public final class WifiBatteryStats implements Parcelable {
return mTimeInSupplicantStateMs;
}
+ public long getMonitoredRailChargeConsumedMaMs() {
+ return mMonitoredRailChargeConsumedMaMs;
+ }
+
public void setLoggingDurationMs(long t) {
mLoggingDurationMs = t;
return;
@@ -245,6 +252,11 @@ public final class WifiBatteryStats implements Parcelable {
return;
}
+ public void setMonitoredRailChargeConsumedMaMs(long monitoredRailEnergyConsumedMaMs) {
+ mMonitoredRailChargeConsumedMaMs = monitoredRailEnergyConsumedMaMs;
+ return;
+ }
+
public int describeContents() {
return 0;
}
@@ -274,6 +286,7 @@ public final class WifiBatteryStats implements Parcelable {
Arrays.fill(mTimeInRxSignalStrengthLevelMs, 0);
mTimeInSupplicantStateMs = new long[BatteryStats.NUM_WIFI_SUPPL_STATES];
Arrays.fill(mTimeInSupplicantStateMs, 0);
+ mMonitoredRailChargeConsumedMaMs = 0;
return;
}
} \ No newline at end of file
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 735f4f253594..43c906495cb6 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1545,7 +1545,7 @@ public class StorageManager {
public static boolean hasIsolatedStorage() {
// Prefer to use snapshot for current boot when available
return SystemProperties.getBoolean(PROP_ISOLATED_STORAGE_SNAPSHOT,
- SystemProperties.getBoolean(PROP_ISOLATED_STORAGE, false));
+ SystemProperties.getBoolean(PROP_ISOLATED_STORAGE, true));
}
/**
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index d67d98c3ab0e..7eb03007ee6a 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -69,42 +69,18 @@ public final class DeviceConfig {
* @hide
*/
@SystemApi
+ @TestApi
public static final String NAMESPACE_AUTOFILL = "autofill";
/**
- * ContentCapture-related properties definitions.
+ * Namespace for content capture feature used by on-device machine intelligence
+ * to provide suggestions in a privacy-safe manner.
*
* @hide
*/
@SystemApi
@TestApi
- public interface ContentCapture {
- String NAMESPACE = "content_capture";
-
- /**
- * Property used by {@code com.android.server.SystemServer} on start to decide whether
- * the Content Capture service should be created or not.
- *
- * <p>Possible values are:
- *
- * <ul>
- * <li>If set to {@code default}, it will only be set if the OEM provides and defines the
- * service name by overlaying {@code config_defaultContentCaptureService} (this is the
- * "default" mode)
- * <li>If set to {@code always}, it will always be enabled, even when the resource is not
- * overlaid (this is useful during development and to run the CTS tests on AOSP builds).
- * <li>Otherwise, it's explicitly disabled (this could work as a "kill switch" so OEMs
- * can disable it remotely in case of emergency by setting to something else (like
- * {@code "false"}); notice that it's also disabled if the OEM doesn't explicitly set one
- * of the values above).
- * </ul>
- *
- * @hide
- */
- // TODO(b/121153631): revert back to SERVICE_EXPLICITLY_ENABLED approach
- @TestApi
- String PROPERTY_CONTENTCAPTURE_ENABLED = "enable_contentcapture";
- }
+ public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
/**
* Namespace for all input-related features that are used at the native level.
@@ -147,6 +123,21 @@ public final class DeviceConfig {
}
/**
+ * Namespace for all runtime related features.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface Runtime {
+ String NAMESPACE = "runtime";
+
+ /**
+ * Whether or not we use the precompiled layout.
+ */
+ String USE_PRECOMPILED_LAYOUT = "view.precompiled_layout_enabled";
+ }
+
+ /**
* Namespace for all runtime native related features.
*
* @hide
@@ -317,6 +308,28 @@ public final class DeviceConfig {
}
/**
+ * Namespace for Rollback.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface Rollback {
+ String NAMESPACE = "rollback";
+
+ String BOOT_NAMESPACE = "rollback_boot";
+
+ /**
+ * Timeout in milliseconds for enabling package rollback.
+ */
+ String ENABLE_ROLLBACK_TIMEOUT = "enable_rollback_timeout";
+
+ /**
+ * The lifetime duration of rollback packages in millis
+ */
+ String ROLLBACK_LIFETIME_IN_MILLIS = "rollback_lifetime_in_millis";
+ }
+
+ /**
* Namespace for storage-related features.
*
* @hide
@@ -333,6 +346,25 @@ public final class DeviceConfig {
String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
}
+ /**
+ * Namespace for system scheduler related features. These features will be applied
+ * immediately upon change.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface Scheduler {
+ String NAMESPACE = "scheduler";
+
+ /**
+ * Flag for enabling fast metrics collection in system scheduler.
+ * A flag value of '' or '0' means the fast metrics collection is not
+ * enabled. Otherwise fast metrics collection is enabled and flag value
+ * is the order id.
+ */
+ String ENABLE_FAST_METRICS_COLLECTION = "enable_fast_metrics_collection";
+ }
+
private static final Object sLock = new Object();
@GuardedBy("sLock")
private static Map<OnPropertyChangedListener, Pair<String, Executor>> sListeners =
@@ -424,6 +456,7 @@ public final class DeviceConfig {
* @see #removeOnPropertyChangedListener(OnPropertyChangedListener)
*/
@SystemApi
+ @TestApi
@RequiresPermission(READ_DEVICE_CONFIG)
public static void addOnPropertyChangedListener(
@NonNull String namespace,
@@ -457,6 +490,7 @@ public final class DeviceConfig {
* @see #addOnPropertyChangedListener(String, Executor, OnPropertyChangedListener)
*/
@SystemApi
+ @TestApi
public static void removeOnPropertyChangedListener(
OnPropertyChangedListener onPropertyChangedListener) {
synchronized (sLock) {
@@ -553,6 +587,7 @@ public final class DeviceConfig {
* @hide
*/
@SystemApi
+ @TestApi
public interface OnPropertyChangedListener {
/**
* Called when a property has changed.
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 5f1c56016fa7..570834265237 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -853,10 +853,8 @@ public final class DocumentsContract {
private static final String PATH_DOCUMENT = "document";
private static final String PATH_CHILDREN = "children";
private static final String PATH_SEARCH = "search";
- // TODO(b/72055774): make private again once ScopedAccessProvider is refactored
- /** {@hide} */
@UnsupportedAppUsage
- public static final String PATH_TREE = "tree";
+ private static final String PATH_TREE = "tree";
private static final String PARAM_QUERY = "query";
private static final String PARAM_MANAGE = "manage";
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index edaf7bb055cf..0b3842080a75 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -157,10 +157,6 @@ public final class MediaStore {
public static final String PARAM_DELETE_DATA = "deletedata";
/** {@hide} */
- public static final String PARAM_PRIMARY = "primary";
- /** {@hide} */
- public static final String PARAM_SECONDARY = "secondary";
- /** {@hide} */
public static final String PARAM_INCLUDE_PENDING = "includePending";
/** {@hide} */
public static final String PARAM_INCLUDE_TRASHED = "includeTrashed";
@@ -582,14 +578,7 @@ public final class MediaStore {
*/
public static @NonNull Uri createPending(@NonNull Context context,
@NonNull PendingParams params) {
- final Uri.Builder builder = params.insertUri.buildUpon();
- if (!TextUtils.isEmpty(params.primaryDirectory)) {
- builder.appendQueryParameter(PARAM_PRIMARY, params.primaryDirectory);
- }
- if (!TextUtils.isEmpty(params.secondaryDirectory)) {
- builder.appendQueryParameter(PARAM_SECONDARY, params.secondaryDirectory);
- }
- return context.getContentResolver().insert(builder.build(), params.insertValues);
+ return context.getContentResolver().insert(params.insertUri, params.insertValues);
}
/**
@@ -612,10 +601,6 @@ public final class MediaStore {
public final Uri insertUri;
/** {@hide} */
public final ContentValues insertValues;
- /** {@hide} */
- public String primaryDirectory;
- /** {@hide} */
- public String secondaryDirectory;
/**
* Create parameters that describe a pending media item.
@@ -657,7 +642,11 @@ public final class MediaStore {
* @see MediaColumns#PRIMARY_DIRECTORY
*/
public void setPrimaryDirectory(@Nullable String primaryDirectory) {
- this.primaryDirectory = primaryDirectory;
+ if (primaryDirectory == null) {
+ this.insertValues.remove(MediaColumns.PRIMARY_DIRECTORY);
+ } else {
+ this.insertValues.put(MediaColumns.PRIMARY_DIRECTORY, primaryDirectory);
+ }
}
/**
@@ -670,7 +659,11 @@ public final class MediaStore {
* @see MediaColumns#SECONDARY_DIRECTORY
*/
public void setSecondaryDirectory(@Nullable String secondaryDirectory) {
- this.secondaryDirectory = secondaryDirectory;
+ if (secondaryDirectory == null) {
+ this.insertValues.remove(MediaColumns.SECONDARY_DIRECTORY);
+ } else {
+ this.insertValues.put(MediaColumns.SECONDARY_DIRECTORY, secondaryDirectory);
+ }
}
/**
@@ -3173,20 +3166,29 @@ public final class MediaStore {
final ArrayList<File> res = new ArrayList<>();
if (VOLUME_INTERNAL.equals(volumeName)) {
- res.add(new File(Environment.getRootDirectory(), "media"));
- res.add(new File(Environment.getOemDirectory(), "media"));
- res.add(new File(Environment.getProductDirectory(), "media"));
+ addCanoncialFile(res, new File(Environment.getRootDirectory(), "media"));
+ addCanoncialFile(res, new File(Environment.getOemDirectory(), "media"));
+ addCanoncialFile(res, new File(Environment.getProductDirectory(), "media"));
} else {
- res.add(getVolumePath(volumeName));
+ addCanoncialFile(res, getVolumePath(volumeName));
final UserManager um = AppGlobals.getInitialApplication()
.getSystemService(UserManager.class);
if (VOLUME_EXTERNAL.equals(volumeName) && um.isDemoUser()) {
- res.add(Environment.getDataPreloadsMediaDirectory());
+ addCanoncialFile(res, Environment.getDataPreloadsMediaDirectory());
}
}
return res;
}
+ private static void addCanoncialFile(List<File> list, File file) {
+ try {
+ list.add(file.getCanonicalFile());
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to resolve " + file + ": " + e);
+ list.add(file);
+ }
+ }
+
/**
* Uri for querying the state of the media scanner.
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index de84e713a6f7..d925d7ee2676 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1657,6 +1657,30 @@ public final class Settings {
public static final String ACTION_STORAGE_VOLUME_ACCESS_SETTINGS =
"android.settings.STORAGE_VOLUME_ACCESS_SETTINGS";
+
+ /**
+ * Activity Action: Show screen that let user select enable (or disable) Content Capture.
+ * <p>
+ * Input: Nothing.
+ *
+ * <p>
+ * Output: {@link android.app.Activity#RESULT_OK} if user enabled Content Capture,
+ * {@link android.app.Activity#RESULT_CANCELED} if user disabled it, cancelled, or if the caller
+ * is not the Content Capture service associated with the user.
+ *
+ * <p>
+ * <b>NOTE: </b> Caller should call
+ * {@link android.view.contentcapture.ContentCaptureManager#isContentCaptureFeatureEnabled()}
+ * first to check whether the feature is already enabled.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE =
+ "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE";
+
// End of Intent actions for Settings
/**
@@ -6103,7 +6127,7 @@ public final class Settings {
* Indicates which clock face to show on lock screen and AOD while docked.
* @hide
*/
- private static final String DOCKED_CLOCK_FACE = "docked_clock_face";
+ public static final String DOCKED_CLOCK_FACE = "docked_clock_face";
/**
* Set by the system to track if the user needs to see the call to action for
@@ -12318,6 +12342,14 @@ public final class Settings {
"angle_whitelist";
/**
+ * Show the "ANGLE In Use" dialog box to the user when ANGLE is the OpenGL driver.
+ * The value is a boolean (1 or 0).
+ * @hide
+ */
+ public static final String GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX =
+ "show_angle_in_use_dialog_box";
+
+ /**
* Game Driver global preference for all Apps.
* 0 = Default
* 1 = All Apps use Game Driver
@@ -12347,6 +12379,12 @@ public final class Settings {
public static final String GAME_DRIVER_BLACKLIST = "game_driver_blacklist";
/**
+ * List of blacklists, each blacklist is a blacklist for a specific version of Game Driver.
+ * @hide
+ */
+ public static final String GAME_DRIVER_BLACKLISTS = "game_driver_blacklists";
+
+ /**
* Apps on the whitelist that are allowed to use Game Driver.
* The string is a list of application package names, seperated by comma.
* i.e. <apk1>,<apk2>,...,<apkN>
@@ -13285,17 +13323,6 @@ public final class Settings {
public static final String AUTOFILL_MAX_VISIBLE_DATASETS = "autofill_max_visible_datasets";
/**
- * Used to emulate Smart Suggestion for Augmented Autofill during development
- *
- * <p>Valid values: {@code 0x1} for IME and/or {@code 0x2} for popup window.
- *
- * @hide
- */
- @TestApi
- public static final String AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS =
- "autofill_smart_suggestion_emulation_flags";
-
- /**
* Exemptions to the hidden API blacklist.
*
* @hide
@@ -13354,6 +13381,14 @@ public final class Settings {
public static final String ISOLATED_STORAGE_REMOTE = "isolated_storage_remote";
/**
+ * Indicates whether aware is available in the current location.
+ * @hide
+ */
+ public static final String AWARE_ALLOWED = "aware_allowed";
+
+ private static final Validator AWARE_ALLOWED_VALIDATOR = BOOLEAN_VALIDATOR;
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
@@ -13399,6 +13434,7 @@ public final class Settings {
SOFT_AP_TIMEOUT_ENABLED,
ZEN_DURATION,
CHARGING_VIBRATION_ENABLED,
+ AWARE_ALLOWED,
};
/**
@@ -13459,6 +13495,7 @@ public final class Settings {
VALIDATORS.put(WIFI_PNO_RECENCY_SORTING_ENABLED,
WIFI_PNO_RECENCY_SORTING_ENABLED_VALIDATOR);
VALIDATORS.put(WIFI_LINK_PROBING_ENABLED, WIFI_LINK_PROBING_ENABLED_VALIDATOR);
+ VALIDATORS.put(AWARE_ALLOWED, AWARE_ALLOWED_VALIDATOR);
}
/**
@@ -14355,6 +14392,7 @@ public final class Settings {
* <pre>
* num_buckets (int)
* collected_uids (string)
+ * minimum_total_cpu_usage_millis (int)
* </pre>
*
* @hide
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 81d066d3d656..8695da237f97 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -61,8 +61,6 @@ import java.util.List;
*/
@SystemApi
@TestApi
-// TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
-// in the same package as the test, and that module is compiled with SDK=test_current
public abstract class AugmentedAutofillService extends Service {
private static final String TAG = AugmentedAutofillService.class.getSimpleName();
diff --git a/core/java/android/service/autofill/augmented/FillCallback.java b/core/java/android/service/autofill/augmented/FillCallback.java
index f2a7a35b2825..b989dd9cd4eb 100644
--- a/core/java/android/service/autofill/augmented/FillCallback.java
+++ b/core/java/android/service/autofill/augmented/FillCallback.java
@@ -31,8 +31,6 @@ import android.util.Log;
*/
@SystemApi
@TestApi
-//TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
-//in the same package as the test, and that module is compiled with SDK=test_current
public final class FillCallback {
private static final String TAG = FillCallback.class.getSimpleName();
diff --git a/core/java/android/service/autofill/augmented/FillController.java b/core/java/android/service/autofill/augmented/FillController.java
index d7bc893f884a..67f23d599e1d 100644
--- a/core/java/android/service/autofill/augmented/FillController.java
+++ b/core/java/android/service/autofill/augmented/FillController.java
@@ -38,10 +38,8 @@ import java.util.List;
*/
@SystemApi
@TestApi
-//TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
-//in the same package as the test, and that module is compiled with SDK=test_current
public final class FillController {
- private static final String TAG = "FillController";
+ private static final String TAG = FillController.class.getSimpleName();
private final AutofillProxy mProxy;
diff --git a/core/java/android/service/autofill/augmented/FillRequest.java b/core/java/android/service/autofill/augmented/FillRequest.java
index af9905f480df..9a97bb203f5a 100644
--- a/core/java/android/service/autofill/augmented/FillRequest.java
+++ b/core/java/android/service/autofill/augmented/FillRequest.java
@@ -31,8 +31,6 @@ import android.view.autofill.AutofillValue;
@SystemApi
// TODO(b/123100811): pass a requestId and/or sessionId?
@TestApi
-// TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
-// in the same package as the test, and that module is compiled with SDK=test_current
public final class FillRequest {
final AutofillProxy mProxy;
diff --git a/core/java/android/service/autofill/augmented/FillResponse.java b/core/java/android/service/autofill/augmented/FillResponse.java
index f1e904a7d8bc..2ac406c5b08c 100644
--- a/core/java/android/service/autofill/augmented/FillResponse.java
+++ b/core/java/android/service/autofill/augmented/FillResponse.java
@@ -30,8 +30,6 @@ import java.util.List;
*/
@SystemApi
@TestApi
-//TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
-//in the same package as the test, and that module is compiled with SDK=test_current
public final class FillResponse {
private final FillWindow mFillWindow;
@@ -53,8 +51,6 @@ public final class FillResponse {
*/
@SystemApi
@TestApi
- //TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
- //in the same package as the test, and that module is compiled with SDK=test_current
public static final class Builder {
private FillWindow mFillWindow;
diff --git a/core/java/android/service/autofill/augmented/FillWindow.java b/core/java/android/service/autofill/augmented/FillWindow.java
index 40e3a1219501..6e06754e7b8a 100644
--- a/core/java/android/service/autofill/augmented/FillWindow.java
+++ b/core/java/android/service/autofill/augmented/FillWindow.java
@@ -63,10 +63,8 @@ import java.io.PrintWriter;
*/
@SystemApi
@TestApi
-//TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
-//in the same package as the test, and that module is compiled with SDK=test_current
public final class FillWindow implements AutoCloseable {
- private static final String TAG = "FillWindow";
+ private static final String TAG = FillWindow.class.getSimpleName();
private final Object mLock = new Object();
private final CloseGuard mCloseGuard = CloseGuard.get();
diff --git a/core/java/android/service/autofill/augmented/PresentationParams.java b/core/java/android/service/autofill/augmented/PresentationParams.java
index 1fb9032c9af5..334487dd6ab4 100644
--- a/core/java/android/service/autofill/augmented/PresentationParams.java
+++ b/core/java/android/service/autofill/augmented/PresentationParams.java
@@ -15,32 +15,19 @@
*/
package android.service.autofill.augmented;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.graphics.Rect;
import android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy;
-import android.util.DebugUtils;
import android.view.View;
import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
/**
* Abstraction of a "Smart Suggestion" component responsible to embed the autofill UI provided by
- * the intelligence service.
- *
- * <p>The Smart Suggestion can embed the autofill UI in 3 distinct places:
- *
- * <ul>
- * <li>A small area associated with suggestions (like a small strip in the top of the IME),
- * returned by {@link #getSuggestionArea()}
- * <li>The full area (like the full IME window), returned by {@link #getFullArea()}
- * <li>A subset of the aforementioned areas, returned by {@link Area#getSubArea(Rect)}
- * </ul>
+ * the augmented autofill service.
*
* <p>The Smart Suggestion is represented by a {@link Area} object that contains the
* dimensions the smart suggestion window, so the service can use it to calculate the size of the
@@ -50,54 +37,8 @@ import java.lang.annotation.RetentionPolicy;
*/
@SystemApi
@TestApi
-//TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
-//in the same package as the test, and that module is compiled with SDK=test_current
public abstract class PresentationParams {
- /**
- * Flag indicating the Smart Suggestion is hosted in the top of its container.
- */
- public static final int FLAG_HINT_GRAVITY_TOP = 0x1;
-
- /**
- * Flag indicating the Smart Suggestion is hosted in the bottom of its container.
- */
- public static final int FLAG_HINT_GRAVITY_BOTTOM = 0x2;
-
- /**
- * Flag indicating the Smart Suggestion is hosted in the left of its container.
- */
- public static final int FLAG_HINT_GRAVITY_LEFT = 0x4;
-
- /**
- * Flag indicating the Smart Suggestion is hosted in the right of its container.
- */
- public static final int FLAG_HINT_GRAVITY_RIGHT = 0x8;
-
- /**
- * Flag indicating the Smart Suggestion is hosted by the IME.
- */
- public static final int FLAG_HOST_IME = 0x10;
-
- /**
- * Flag indicating the Smart Suggestion is hosted by the Android System as a floating popup
- * window.
- */
- public static final int FLAG_HOST_SYSTEM = 0x20;
-
- /** @hide */
- @IntDef(flag = true, prefix = { "FLAG_" }, value = {
- FLAG_HINT_GRAVITY_TOP,
- FLAG_HINT_GRAVITY_BOTTOM,
- FLAG_HINT_GRAVITY_LEFT,
- FLAG_HINT_GRAVITY_RIGHT,
- FLAG_HOST_IME,
- FLAG_HOST_SYSTEM
- })
- @Retention(RetentionPolicy.SOURCE)
- @interface Flags {}
-
-
// /** @hide */
PresentationParams() {}
@@ -112,40 +53,7 @@ public abstract class PresentationParams {
return null;
}
- /**
- * Gets the full area for the of the Smart Suggestion provider.
- *
- * @return full dimensions, or {@code null} if the Smart Suggestion provider does not support
- * embeding the UI on its full area.
- */
- @Nullable
- public Area getFullArea() {
- return null;
- }
-
- /**
- * Gets flags associated with the Smart Suggestion.
- *
- * @return any combination of {@link #FLAG_HINT_GRAVITY_TOP},
- * {@link #FLAG_HINT_GRAVITY_BOTTOM}, {@link #FLAG_HINT_GRAVITY_LEFT},
- * {@link #FLAG_HINT_GRAVITY_RIGHT}, {@link #FLAG_HOST_IME}, or
- * {@link #FLAG_HOST_SYSTEM},
- */
- public @Flags int getFlags() {
- return 0;
- }
-
- /** @hide */
- void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
- final int flags = getFlags();
- if (flags > 0) {
- pw.print(prefix); pw.print("flags: "); pw.println(flagsToString(flags));
- }
- }
-
- private static String flagsToString(int flags) {
- return DebugUtils.flagsToString(PresentationParams.class, "FLAG_", flags);
- }
+ abstract void dump(String prefix, PrintWriter pw);
/**
* Area associated with a {@link PresentationParams Smart Suggestions} provider.
@@ -154,8 +62,6 @@ public abstract class PresentationParams {
*/
@SystemApi
@TestApi
- //TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
- //in the same package as the test, and that module is compiled with SDK=test_current
public abstract static class Area {
/** @hide */
@@ -176,24 +82,6 @@ public abstract class PresentationParams {
return mBounds;
}
- /**
- * Gets a subarea limited by given boundaries.
- *
- * @param bounds boundaries relative to this Area.
- *
- * @return new subarea, or {@code null} if the Smart Suggestion host does not support such
- * subaarea.
- *
- * @throws IllegalArgumentException if the {@code bounds} is not fully-contained inside this
- * full Area.
- *
- */
- @Nullable
- public Area getSubArea(@NonNull Rect bounds) {
- // TODO(b/123100712): implement / check boundaries / throw IAE / add unit test
- return null;
- }
-
@Override
public String toString() {
return mBounds.toString();
@@ -220,13 +108,7 @@ public abstract class PresentationParams {
}
@Override
- public int getFlags() {
- return FLAG_HOST_SYSTEM | FLAG_HINT_GRAVITY_BOTTOM;
- }
-
- @Override
void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
- super.dump(prefix, pw);
pw.print(prefix); pw.print("area: "); pw.println(mSuggestionArea);
}
}
diff --git a/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
index ca6676d87479..bbcf7a9c97b1 100644
--- a/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
+++ b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
@@ -28,7 +28,8 @@ import java.util.List;
/**
* Not needed anymore...
*
- * @deprecated
+ * @deprecated ContentCaptureService should use
+ * {@code #onContentCaptureEvent(ContentCaptureSessionId, ContentCaptureEvent)} instead.
*
* @hide
*/
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index c98f09e13d97..d2f98599e9a6 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -339,7 +339,7 @@ public abstract class ContentCaptureService extends Service {
}
switch (event.getType()) {
case ContentCaptureEvent.TYPE_SESSION_STARTED:
- final ContentCaptureContext clientContext = event.getClientContext();
+ final ContentCaptureContext clientContext = event.getContentCaptureContext();
clientContext.setParentSessionId(event.getParentSessionId());
mSessionUids.put(sessionIdString, uid);
onCreateContentCaptureSession(clientContext, sessionId);
@@ -383,8 +383,8 @@ public abstract class ContentCaptureService extends Service {
}
final Integer rightUid = mSessionUids.get(sessionId);
if (rightUid == null) {
- if (DEBUG) {
- Log.d(TAG, "handleIsRightCallerFor(" + event + "): no session for " + sessionId
+ if (VERBOSE) {
+ Log.v(TAG, "handleIsRightCallerFor(" + event + "): no session for " + sessionId
+ ": " + mSessionUids);
}
// Just ignore, as the session could have been finished already
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index ffb524d5c2e4..a46d04765e2c 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -76,6 +76,11 @@ import java.util.concurrent.atomic.AtomicInteger;
* filter with the appropriate action, the {@link #CATEGORY_EUICC_UI} category, and a non-zero
* priority.
*
+ * <p>Old implementations of EuiccService may support passing in slot IDs equal to
+ * {@link android.telephony.SubscriptionManager#INVALID_SIM_SLOT_INDEX}, which allows the LPA to
+ * decide which eUICC to target when there are multiple eUICCs. This behavior is not supported in
+ * Android Q or later.
+ *
* @hide
*/
@SystemApi
@@ -546,7 +551,7 @@ public abstract class EuiccService extends Service {
int resultCode = EuiccService.this.onDownloadSubscription(
slotId, subscription, switchAfterDownload, forceDeactivateSim);
result = new DownloadSubscriptionResult(resultCode,
- 0 /* resolvableErrors */, TelephonyManager.INVALID_CARD_ID);
+ 0 /* resolvableErrors */, TelephonyManager.UNSUPPORTED_CARD_ID);
}
try {
callback.onComplete(result);
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 551bb8ada044..954dc3943019 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -372,6 +372,13 @@ public class StatusBarNotification implements Parcelable {
/**
* @hide
*/
+ public void clearPackageContext() {
+ mContext = null;
+ }
+
+ /**
+ * @hide
+ */
@UnsupportedAppUsage
public Context getPackageContext(Context context) {
if (mContext == null) {
diff --git a/core/java/android/service/textclassifier/TEST_MAPPING b/core/java/android/service/textclassifier/TEST_MAPPING
new file mode 100644
index 000000000000..ccf26315852d
--- /dev/null
+++ b/core/java/android/service/textclassifier/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/base/core/java/android/view/textclassifier"
+ }
+ ]
+}
diff --git a/core/java/android/text/style/DynamicDrawableSpan.java b/core/java/android/text/style/DynamicDrawableSpan.java
index be772af529ef..575401458691 100644
--- a/core/java/android/text/style/DynamicDrawableSpan.java
+++ b/core/java/android/text/style/DynamicDrawableSpan.java
@@ -77,6 +77,13 @@ public abstract class DynamicDrawableSpan extends ReplacementSpan {
*/
public static final int ALIGN_BASELINE = 1;
+ /**
+ * A constant indicating that this span should be vertically centered between
+ * the top and the lowest descender.
+ * @hide
+ */
+ public static final int ALIGN_CENTER = 2;
+
protected final int mVerticalAlignment;
@UnsupportedAppUsage
@@ -142,6 +149,8 @@ public abstract class DynamicDrawableSpan extends ReplacementSpan {
int transY = bottom - b.getBounds().bottom;
if (mVerticalAlignment == ALIGN_BASELINE) {
transY -= paint.getFontMetricsInt().descent;
+ } else if (mVerticalAlignment == ALIGN_CENTER) {
+ transY = (bottom - top) / 2 - b.getBounds().height() / 2;
}
canvas.translate(x, transY);
diff --git a/core/java/android/util/MathUtils.java b/core/java/android/util/MathUtils.java
index 56558d04e50d..0eeef70a79a6 100644
--- a/core/java/android/util/MathUtils.java
+++ b/core/java/android/util/MathUtils.java
@@ -166,6 +166,26 @@ public final class MathUtils {
}
/**
+ * Returns the interpolation scalar (s) that satisfies the equation: {@code value = }{@link
+ * #lerp}{@code (a, b, s)}
+ *
+ * <p>If {@code a == b}, then this function will return 0.
+ */
+ public static float lerpInv(float a, float b, float value) {
+ return a != b ? ((value - a) / (b - a)) : 0.0f;
+ }
+
+ /** Returns the single argument constrained between [0.0, 1.0]. */
+ public static float saturate(float value) {
+ return constrain(value, 0.0f, 1.0f);
+ }
+
+ /** Returns the saturated (constrained between [0, 1]) result of {@link #lerpInv}. */
+ public static float lerpInvSat(float a, float b, float value) {
+ return saturate(lerpInv(a, b, value));
+ }
+
+ /**
* Returns an interpolated angle in degrees between a set of start and end
* angles.
* <p>
@@ -195,6 +215,32 @@ public final class MathUtils {
}
/**
+ * Calculates a value in [rangeMin, rangeMax] that maps value in [valueMin, valueMax] to
+ * returnVal in [rangeMin, rangeMax].
+ * <p>
+ * Always returns a constrained value in the range [rangeMin, rangeMax], even if value is
+ * outside [valueMin, valueMax].
+ * <p>
+ * Eg:
+ * constrainedMap(0f, 100f, 0f, 1f, 0.5f) = 50f
+ * constrainedMap(20f, 200f, 10f, 20f, 20f) = 200f
+ * constrainedMap(20f, 200f, 10f, 20f, 50f) = 200f
+ * constrainedMap(10f, 50f, 10f, 20f, 5f) = 10f
+ *
+ * @param rangeMin minimum of the range that should be returned.
+ * @param rangeMax maximum of the range that should be returned.
+ * @param valueMin minimum of range to map {@code value} to.
+ * @param valueMax maximum of range to map {@code value} to.
+ * @param value to map to the range [{@code valueMin}, {@code valueMax}]. Note, can be outside
+ * this range, resulting in a clamped value.
+ * @return the mapped value, constrained to [{@code rangeMin}, {@code rangeMax}.
+ */
+ public static float constrainedMap(
+ float rangeMin, float rangeMax, float valueMin, float valueMax, float value) {
+ return lerp(rangeMin, rangeMax, lerpInvSat(valueMin, valueMax, value));
+ }
+
+ /**
* Perform Hermite interpolation between two values.
* Eg:
* smoothStep(0, 0.5f, 0.5f) = 1f
diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java
index ace4bf477af6..29ced3eda4ec 100644
--- a/core/java/android/util/StatsLog.java
+++ b/core/java/android/util/StatsLog.java
@@ -16,7 +16,14 @@
package android.util;
+import static android.Manifest.permission.DUMP;
+import static android.Manifest.permission.PACKAGE_USAGE_STATS;
+
+import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.app.IActivityManager;
+import android.content.Context;
import android.os.IStatsManager;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -31,7 +38,10 @@ public final class StatsLog extends StatsLogInternal {
private static IStatsManager sService;
- private StatsLog() {}
+ private static Object sLogLock = new Object();
+
+ private StatsLog() {
+ }
/**
* Logs a start event.
@@ -40,11 +50,13 @@ public final class StatsLog extends StatsLogInternal {
* @return True if the log request was sent to statsd.
*/
public static boolean logStart(int label) {
- synchronized (StatsLog.class) {
+ synchronized (sLogLock) {
try {
IStatsManager service = getIStatsManagerLocked();
if (service == null) {
- if (DEBUG) Slog.d(TAG, "Failed to find statsd when logging start");
+ if (DEBUG) {
+ Slog.d(TAG, "Failed to find statsd when logging start");
+ }
return false;
}
service.sendAppBreadcrumbAtom(label,
@@ -52,7 +64,9 @@ public final class StatsLog extends StatsLogInternal {
return true;
} catch (RemoteException e) {
sService = null;
- if (DEBUG) Slog.d(TAG, "Failed to connect to statsd when logging start");
+ if (DEBUG) {
+ Slog.d(TAG, "Failed to connect to statsd when logging start");
+ }
return false;
}
}
@@ -65,18 +79,22 @@ public final class StatsLog extends StatsLogInternal {
* @return True if the log request was sent to statsd.
*/
public static boolean logStop(int label) {
- synchronized (StatsLog.class) {
+ synchronized (sLogLock) {
try {
IStatsManager service = getIStatsManagerLocked();
if (service == null) {
- if (DEBUG) Slog.d(TAG, "Failed to find statsd when logging stop");
+ if (DEBUG) {
+ Slog.d(TAG, "Failed to find statsd when logging stop");
+ }
return false;
}
service.sendAppBreadcrumbAtom(label, StatsLog.APP_BREADCRUMB_REPORTED__STATE__STOP);
return true;
} catch (RemoteException e) {
sService = null;
- if (DEBUG) Slog.d(TAG, "Failed to connect to statsd when logging stop");
+ if (DEBUG) {
+ Slog.d(TAG, "Failed to connect to statsd when logging stop");
+ }
return false;
}
}
@@ -89,11 +107,13 @@ public final class StatsLog extends StatsLogInternal {
* @return True if the log request was sent to statsd.
*/
public static boolean logEvent(int label) {
- synchronized (StatsLog.class) {
+ synchronized (sLogLock) {
try {
IStatsManager service = getIStatsManagerLocked();
if (service == null) {
- if (DEBUG) Slog.d(TAG, "Failed to find statsd when logging event");
+ if (DEBUG) {
+ Slog.d(TAG, "Failed to find statsd when logging event");
+ }
return false;
}
service.sendAppBreadcrumbAtom(
@@ -101,7 +121,51 @@ public final class StatsLog extends StatsLogInternal {
return true;
} catch (RemoteException e) {
sService = null;
- if (DEBUG) Slog.d(TAG, "Failed to connect to statsd when logging event");
+ if (DEBUG) {
+ Slog.d(TAG, "Failed to connect to statsd when logging event");
+ }
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Logs an event for binary push for module updates.
+ *
+ * @param trainName name of install train.
+ * @param trainVersionCode version code of the train.
+ * @param options optional flags about this install.
+ * @param state current install state.
+ * @param experimentIds experiment ids.
+ * @return True if the log request was sent to statsd.
+ */
+ @RequiresPermission(allOf = {DUMP, PACKAGE_USAGE_STATS})
+ public static boolean logBinaryPushStateChanged(@NonNull String trainName,
+ long trainVersionCode, int options, int state,
+ @NonNull long[] experimentIds) {
+ synchronized (sLogLock) {
+ try {
+ IStatsManager service = getIStatsManagerLocked();
+ if (service == null) {
+ if (DEBUG) {
+ Slog.d(TAG, "Failed to find statsd when logging event");
+ }
+ return false;
+ }
+ int userId = IActivityManager.Stub.asInterface(
+ ServiceManager.getService("activity"))
+ .getCurrentUser()
+ .id;
+ service.sendBinaryPushStateChangedAtom(
+ trainName, trainVersionCode, options, state, experimentIds);
+ return true;
+ } catch (RemoteException e) {
+ sService = null;
+ if (DEBUG) {
+ Slog.d(TAG,
+ "Failed to connect to StatsCompanionService when logging "
+ + "BinaryPushStateChanged");
+ }
return false;
}
}
@@ -118,7 +182,7 @@ public final class StatsLog extends StatsLogInternal {
/**
* Add a log to the stats log.
*
- * @param id The id of the atom
+ * @param id The id of the atom
* @param params The parameters of the atom's message.
*/
public static void write(int id, @NonNull Object... params) {
@@ -128,4 +192,13 @@ public final class StatsLog extends StatsLogInternal {
(boolean) params[4], (int) params[5]);
}
}
+
+ private static void enforceDumpCallingPermission(Context context) {
+ context.enforceCallingPermission(android.Manifest.permission.DUMP, "Need DUMP permission.");
+ }
+
+ private static void enforcesageStatsCallingPermission(Context context) {
+ context.enforceCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS,
+ "Need PACKAGE_USAGE_STATS permission.");
+ }
}
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 62ed901c5e06..f37c9162d98a 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -336,7 +336,7 @@ public final class AccessibilityInteractionController {
}
mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags;
final View root = findViewByAccessibilityId(accessibilityViewId);
- if (root != null) {
+ if (root != null && isShown(root)) {
mPrefetcher.prefetchAccessibilityNodeInfos(
root, virtualDescendantId, flags, infos, arguments);
}
@@ -448,7 +448,7 @@ public final class AccessibilityInteractionController {
}
mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags;
final View root = findViewByAccessibilityId(accessibilityViewId);
- if (root != null) {
+ if (root != null && isShown(root)) {
AccessibilityNodeProvider provider = root.getAccessibilityNodeProvider();
if (provider != null) {
infos = provider.findAccessibilityNodeInfosByText(text,
@@ -531,7 +531,7 @@ public final class AccessibilityInteractionController {
}
mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags;
final View root = findViewByAccessibilityId(accessibilityViewId);
- if (root != null) {
+ if (root != null && isShown(root)) {
switch (focusType) {
case AccessibilityNodeInfo.FOCUS_ACCESSIBILITY: {
View host = mViewRootImpl.mAccessibilityFocusedHost;
@@ -621,7 +621,7 @@ public final class AccessibilityInteractionController {
}
mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags;
final View root = findViewByAccessibilityId(accessibilityViewId);
- if (root != null) {
+ if (root != null && isShown(root)) {
View nextView = root.focusSearch(direction);
if (nextView != null) {
next = nextView.createAccessibilityNodeInfo();
@@ -676,7 +676,7 @@ public final class AccessibilityInteractionController {
}
mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags;
final View target = findViewByAccessibilityId(accessibilityViewId);
- if (target != null) {
+ if (target != null && isShown(target)) {
if (action == R.id.accessibilityActionClickOnClickableSpan) {
// Handle this hidden action separately
succeeded = handleClickableSpanActionUiThread(
@@ -759,9 +759,7 @@ public final class AccessibilityInteractionController {
if (accessibilityId == AccessibilityNodeInfo.ROOT_ITEM_ID) {
return mViewRootImpl.mView;
} else {
- final View foundView =
- AccessibilityNodeIdManager.getInstance().findView(accessibilityId);
- return isShown(foundView) ? foundView : null;
+ return AccessibilityNodeIdManager.getInstance().findView(accessibilityId);
}
}
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 03e8a0fc0d39..c64386e8db79 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -133,7 +133,7 @@ public final class Choreographer {
};
// Enable/disable vsync for animations and drawing.
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769497)
private static final boolean USE_VSYNC = SystemProperties.getBoolean(
"debug.choreographer.vsync", true);
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index e3a6bd7a6949..cb5100a4d57a 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -32,6 +32,7 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
@@ -75,7 +76,7 @@ public final class Display {
private final int mLayerStack;
private final int mFlags;
private final int mType;
- private final String mAddress;
+ private final DisplayAddress mAddress;
private final int mOwnerUid;
private final String mOwnerPackageName;
private final Resources mResources;
@@ -495,7 +496,7 @@ public final class Display {
* @return True if the display is still valid.
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public boolean getDisplayInfo(DisplayInfo outDisplayInfo) {
synchronized (this) {
updateDisplayInfoLocked();
@@ -556,7 +557,7 @@ public final class Display {
* @hide
*/
@UnsupportedAppUsage
- public String getAddress() {
+ public DisplayAddress getAddress() {
return mAddress;
}
diff --git a/core/java/android/view/DisplayAddress.java b/core/java/android/view/DisplayAddress.java
new file mode 100644
index 000000000000..17ea4c423be5
--- /dev/null
+++ b/core/java/android/view/DisplayAddress.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** Display identifier that is stable across reboots.
+ *
+ * @hide
+ */
+public abstract class DisplayAddress implements Parcelable {
+ /**
+ * Creates an address for a physical display given its stable ID.
+ *
+ * A physical display ID is stable if the display can be identified using EDID information.
+ *
+ * @param physicalDisplayId A physical display ID.
+ * @return The {@link Physical} address, or {@code null} if the ID is not stable.
+ * @see SurfaceControl#getPhysicalDisplayIds
+ */
+ @Nullable
+ public static Physical fromPhysicalDisplayId(long physicalDisplayId) {
+ final Physical address = new Physical(physicalDisplayId);
+ return address.getModel() == 0 ? null : address;
+ }
+
+ /**
+ * Creates an address for a network display given its MAC address.
+ *
+ * @param macAddress A MAC address in colon notation.
+ * @return The {@link Network} address.
+ */
+ @NonNull
+ public static Network fromMacAddress(String macAddress) {
+ return new Network(macAddress);
+ }
+
+ /**
+ * Address for a physically connected display.
+ *
+ * A {@link Physical} address is represented by a 64-bit identifier combining the port and model
+ * of a display. The port, located in the least significant byte, uniquely identifies a physical
+ * connector on the device for display output like eDP or HDMI. The model, located in the upper
+ * bits, uniquely identifies a display model across manufacturers by encoding EDID information.
+ */
+ public static final class Physical extends DisplayAddress {
+ private static final int PHYSICAL_DISPLAY_ID_MODEL_SHIFT = 8;
+ private static final int PORT_MASK = 0xFF;
+
+ private final long mPhysicalDisplayId;
+
+ /**
+ * Physical port to which the display is connected.
+ */
+ public byte getPort() {
+ return (byte) mPhysicalDisplayId;
+ }
+
+ /**
+ * Model identifier unique across manufacturers.
+ */
+ public long getModel() {
+ return mPhysicalDisplayId >>> PHYSICAL_DISPLAY_ID_MODEL_SHIFT;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other instanceof Physical
+ && mPhysicalDisplayId == ((Physical) other).mPhysicalDisplayId;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder("{")
+ .append("port=").append(getPort() & PORT_MASK)
+ .append(", model=0x").append(Long.toHexString(getModel()))
+ .append("}")
+ .toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return Long.hashCode(mPhysicalDisplayId);
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeLong(mPhysicalDisplayId);
+ }
+
+ private Physical(long physicalDisplayId) {
+ mPhysicalDisplayId = physicalDisplayId;
+ }
+
+ public static final Parcelable.Creator<Physical> CREATOR =
+ new Parcelable.Creator<Physical>() {
+ @Override
+ public Physical createFromParcel(Parcel in) {
+ return new Physical(in.readLong());
+ }
+
+ @Override
+ public Physical[] newArray(int size) {
+ return new Physical[size];
+ }
+ };
+ }
+
+ /**
+ * Address for a network-connected display.
+ */
+ public static final class Network extends DisplayAddress {
+ private final String mMacAddress;
+
+ @Override
+ public boolean equals(Object other) {
+ return other instanceof Network && mMacAddress.equals(((Network) other).mMacAddress);
+ }
+
+ @Override
+ public String toString() {
+ return mMacAddress;
+ }
+
+ @Override
+ public int hashCode() {
+ return mMacAddress.hashCode();
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mMacAddress);
+ }
+
+ private Network(String macAddress) {
+ mMacAddress = macAddress;
+ }
+
+ public static final Parcelable.Creator<Network> CREATOR =
+ new Parcelable.Creator<Network>() {
+ @Override
+ public Network createFromParcel(Parcel in) {
+ return new Network(in.readString());
+ }
+
+ @Override
+ public Network[] newArray(int size) {
+ return new Network[size];
+ }
+ };
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index ff4ee9ce7ded..3aa779bc3df6 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -61,7 +61,7 @@ public final class DisplayInfo implements Parcelable {
* Display address, or null if none.
* Interpretation varies by display type.
*/
- public String address;
+ public DisplayAddress address;
/**
* The human-readable name of the display.
@@ -158,8 +158,9 @@ public final class DisplayInfo implements Parcelable {
*
* @hide
*/
+ // Remark on @UnsupportedAppUsage: Display.getCutout should be used instead
@Nullable
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public DisplayCutout displayCutout;
/**
@@ -384,7 +385,7 @@ public final class DisplayInfo implements Parcelable {
layerStack = source.readInt();
flags = source.readInt();
type = source.readInt();
- address = source.readString();
+ address = source.readParcelable(null);
name = source.readString();
appWidth = source.readInt();
appHeight = source.readInt();
@@ -431,7 +432,7 @@ public final class DisplayInfo implements Parcelable {
dest.writeInt(layerStack);
dest.writeInt(this.flags);
dest.writeInt(type);
- dest.writeString(address);
+ dest.writeParcelable(address, flags);
dest.writeString(name);
dest.writeInt(appWidth);
dest.writeInt(appHeight);
diff --git a/core/java/android/view/GhostView.java b/core/java/android/view/GhostView.java
index 74c801b1dc5b..3286bd623694 100644
--- a/core/java/android/view/GhostView.java
+++ b/core/java/android/view/GhostView.java
@@ -20,6 +20,7 @@ import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.RecordingCanvas;
import android.graphics.RenderNode;
+import android.os.Build;
import android.widget.FrameLayout;
import java.util.ArrayList;
@@ -135,12 +136,12 @@ public class GhostView extends View {
return ghostView;
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public static GhostView addGhost(View view, ViewGroup viewGroup) {
return addGhost(view, viewGroup, null);
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public static void removeGhost(View view) {
GhostView ghostView = view.mGhostView;
if (ghostView != null) {
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 7295259a0f89..868a9de93972 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -22,6 +22,7 @@ import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
+import android.os.Build;
import android.os.NullVibrator;
import android.os.Parcel;
import android.os.Parcelable;
@@ -54,7 +55,7 @@ public final class InputDevice implements Parcelable {
private final int mProductId;
private final String mDescriptor;
private final InputDeviceIdentifier mIdentifier;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private final boolean mIsExternal;
private final int mSources;
private final int mKeyboardType;
@@ -608,10 +609,7 @@ public final class InputDevice implements Parcelable {
* peripheral bus), otherwise it is built-in.
*
* @return True if the device is external.
- *
- * @hide
*/
- @UnsupportedAppUsage
public boolean isExternal() {
return mIsExternal;
}
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 3f18d8b46e2a..f13cb5a197d8 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -33,6 +33,8 @@ import android.os.Handler;
import android.os.Message;
import android.os.SystemProperties;
import android.os.Trace;
+import android.provider.DeviceConfig;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
@@ -80,8 +82,6 @@ public abstract class LayoutInflater {
private static final String TAG = LayoutInflater.class.getSimpleName();
private static final boolean DEBUG = false;
- private static final String USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY
- = "view.precompiled_layout_enabled";
private static final String COMPILED_VIEW_DEX_FILE_NAME = "/compiled_view.dex";
/** Empty stack trace used to avoid log spam in re-throw exceptions. */
@@ -95,7 +95,12 @@ public abstract class LayoutInflater {
protected final Context mContext;
// these are optional, set by the caller
- @UnsupportedAppUsage
+ /**
+ * If any developer has desire to change this value, they should instead use
+ * {@link #cloneInContext(Context)} and set the new factory in thew newly-created
+ * LayoutInflater.
+ */
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private boolean mFactorySet;
@UnsupportedAppUsage
private Factory mFactory;
@@ -124,7 +129,7 @@ public abstract class LayoutInflater {
static final Class<?>[] mConstructorSignature = new Class[] {
Context.class, AttributeSet.class};
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769490)
private static final HashMap<String, Constructor<? extends View>> sConstructorMap =
new HashMap<String, Constructor<? extends View>>();
@@ -407,8 +412,24 @@ public abstract class LayoutInflater {
}
private void initPrecompiledViews() {
- initPrecompiledViews(
- SystemProperties.getBoolean(USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY, false));
+ // Use the device config if enabled, otherwise default to the system property.
+ String usePrecompiledLayout = null;
+ try {
+ usePrecompiledLayout = DeviceConfig.getProperty(
+ DeviceConfig.Runtime.NAMESPACE,
+ DeviceConfig.Runtime.USE_PRECOMPILED_LAYOUT);
+ } catch (Exception e) {
+ // May be caused by permission errors reading the property (i.e. instant apps).
+ }
+ boolean enabled = false;
+ if (TextUtils.isEmpty(usePrecompiledLayout)) {
+ enabled = SystemProperties.getBoolean(
+ DeviceConfig.Runtime.USE_PRECOMPILED_LAYOUT,
+ false);
+ } else {
+ enabled = Boolean.parseBoolean(usePrecompiledLayout);
+ }
+ initPrecompiledViews(enabled);
}
private void initPrecompiledViews(boolean enablePrecompiledViews) {
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index b6a4a095066f..b6c4cbbbe54d 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -24,6 +24,7 @@ import android.annotation.IntDef;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.graphics.Matrix;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -1513,7 +1514,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
}
// Pointer to the native MotionEvent object that contains the actual data.
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private long mNativePtr;
private MotionEvent mNext;
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index 1dbc46b3e883..6cfc9f22a692 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -25,6 +25,7 @@ import android.graphics.Paint;
import android.graphics.RecordingCanvas;
import android.graphics.RenderNode;
import android.os.Build;
+import android.os.Handler;
import android.util.SparseIntArray;
import com.android.internal.util.VirtualRefBasePtr;
@@ -84,6 +85,7 @@ public class RenderNodeAnimator extends Animator {
private VirtualRefBasePtr mNativePtr;
+ private Handler mHandler;
private RenderNode mTarget;
private View mViewTarget;
private int mRenderProperty = -1;
@@ -222,6 +224,9 @@ public class RenderNodeAnimator extends Animator {
private void moveToRunningState() {
mState = STATE_RUNNING;
if (mNativePtr != null) {
+ if (mHandler == null) {
+ mHandler = new Handler();
+ }
nStart(mNativePtr.get());
}
notifyStartListeners();
@@ -497,7 +502,7 @@ public class RenderNodeAnimator extends Animator {
// Called by native
@UnsupportedAppUsage
private static void callOnFinished(RenderNodeAnimator animator) {
- animator.onFinished();
+ animator.mHandler.post(animator::onFinished);
}
@Override
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index dc11d3ddd1d6..c24b8b2a5ee3 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -18,7 +18,6 @@ package android.view;
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
-import android.content.res.Resources;
import android.os.Build;
import android.os.Handler;
@@ -145,7 +144,7 @@ public class ScaleGestureDetector {
private boolean mInProgress;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768938)
private int mSpanSlop;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768938)
private int mMinSpan;
private final Handler mHandler;
@@ -200,10 +199,9 @@ public class ScaleGestureDetector {
Handler handler) {
mContext = context;
mListener = listener;
- mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;
-
- final Resources res = context.getResources();
- mMinSpan = res.getDimensionPixelSize(com.android.internal.R.dimen.config_minScalingSpan);
+ final ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
+ mSpanSlop = viewConfiguration.getScaledTouchSlop() * 2;
+ mMinSpan = viewConfiguration.getScaledMinScalingSpan();
mHandler = handler;
// Quick scale is enabled by default after JB_MR2
final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 47b206ca0dca..20978127f510 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -453,7 +453,7 @@ public final class ThreadedRenderer extends HardwareRenderer {
*/
void destroyHardwareResources(View view) {
destroyResources(view);
- destroyHardwareResources();
+ clearContent();
}
private static void destroyResources(View view) {
@@ -735,7 +735,9 @@ public final class ThreadedRenderer extends HardwareRenderer {
if (callback != null) {
setFrameCallback(callback);
}
- syncAndDrawFrame(vsync);
+ createRenderRequest()
+ .setVsyncTime(vsync)
+ .syncAndDraw();
}
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3f2795ba1e00..2b440dc80cfd 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -24,6 +24,7 @@ import static java.lang.Math.max;
import android.animation.AnimatorInflater;
import android.animation.StateListAnimator;
+import android.annotation.AttrRes;
import android.annotation.CallSuper;
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
@@ -4030,8 +4031,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* {@hide}
+ *
+ * Not available for general use. If you need help, hang up and then dial one of the following
+ * public APIs:
+ *
+ * @see #isAttachedToWindow() for current attach state
+ * @see #onAttachedToWindow() for subclasses performing work when becoming attached
+ * @see #onDetachedFromWindow() for subclasses performing work when becoming detached
+ * @see OnAttachStateChangeListener for other code performing work on attach/detach
+ * @see #getHandler() for posting messages to this view's UI thread/looper
+ * @see #getParent() for interacting with the parent chain
+ * @see #getWindowToken() for the current window token
+ * @see #getRootView() for the view at the root of the attached hierarchy
+ * @see #getDisplay() for the Display this view is presented on
+ * @see #getRootWindowInsets() for the current insets applied to the whole attached window
+ * @see #hasWindowFocus() for whether the attached window is currently focused
+ * @see #getWindowVisibility() for checking the visibility of the attached window
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
AttachInfo mAttachInfo;
/**
@@ -5092,7 +5109,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private SparseIntArray mAttributeSourceResId;
@Nullable
- private int[] mAttributeResolutionStack;
+ private SparseArray<int[]> mAttributeResolutionStacks;
@StyleRes
private int mExplicitStyle;
@@ -5947,11 +5964,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* <b>Note:</b> this method will only return actual values if the view attribute debugging
* is enabled in Android developer options.
*
+ * @param attribute Attribute resource ID for which the resolution stack should be returned.
* @return ordered list of resource ID that are considered when resolving attribute values for
* this {@link View}.
*/
@NonNull
- public List<Integer> getAttributeResolutionStack() {
+ public List<Integer> getAttributeResolutionStack(@AttrRes int attribute) {
ArrayList<Integer> stack = new ArrayList<>();
if (!sDebugViewAttributes) {
return stack;
@@ -5959,8 +5977,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (mSourceLayoutId != ID_NULL) {
stack.add(mSourceLayoutId);
}
- for (int i = 0; i < mAttributeResolutionStack.length; i++) {
- stack.add(mAttributeResolutionStack[i]);
+ int[] attributeResolutionStack = mAttributeResolutionStacks.get(attribute);
+ if (attributeResolutionStack == null) {
+ return stack;
+ }
+ for (int i = 0; i < attributeResolutionStack.length; i++) {
+ stack.add(attributeResolutionStack[i]);
}
return stack;
}
@@ -6127,9 +6149,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return;
}
- mAttributeResolutionStack = context.getTheme().getAttributeResolutionStack(
+ int[] attributeResolutionStack = context.getTheme().getAttributeResolutionStack(
defStyleAttr, defStyleRes, mExplicitStyle);
+ if (mAttributeResolutionStacks == null) {
+ mAttributeResolutionStacks = new SparseArray<>();
+ }
+
if (mAttributeSourceResId == null) {
mAttributeSourceResId = new SparseIntArray();
}
@@ -6138,6 +6164,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
for (int j = 0; j < indexCount; ++j) {
final int index = t.getIndex(j);
mAttributeSourceResId.append(styleable[index], t.getSourceResourceId(index, 0));
+ mAttributeResolutionStacks.append(styleable[index], attributeResolutionStack);
}
}
@@ -6440,6 +6467,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
arr.recycle();
}
+ private void initializeScrollBarDrawable() {
+ initScrollCache();
+
+ if (mScrollCache.scrollBar == null) {
+ mScrollCache.scrollBar = new ScrollBarDrawable();
+ mScrollCache.scrollBar.setState(getDrawableState());
+ mScrollCache.scrollBar.setCallback(this);
+ }
+ }
+
/**
* <p>
* Initializes the scrollbars from a given set of styled attributes. This
@@ -6525,6 +6562,106 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
resolvePadding();
}
+ /**
+ * Defines the vertical scrollbar thumb drawable
+ * @attr ref android.R.styleable#View_scrollbarThumbVertical
+ *
+ * @see #awakenScrollBars(int)
+ * @see #isVerticalScrollBarEnabled()
+ * @see #setVerticalScrollBarEnabled(boolean)
+ */
+ public void setVerticalScrollbarThumbDrawable(@Nullable Drawable drawable) {
+ initializeScrollBarDrawable();
+ mScrollCache.scrollBar.setVerticalThumbDrawable(drawable);
+ }
+
+ /**
+ * Defines the vertical scrollbar track drawable
+ * @attr ref android.R.styleable#View_scrollbarTrackVertical
+ *
+ * @see #awakenScrollBars(int)
+ * @see #isVerticalScrollBarEnabled()
+ * @see #setVerticalScrollBarEnabled(boolean)
+ */
+ public void setVerticalScrollbarTrackDrawable(@Nullable Drawable drawable) {
+ initializeScrollBarDrawable();
+ mScrollCache.scrollBar.setVerticalTrackDrawable(drawable);
+ }
+
+ /**
+ * Defines the horizontal thumb drawable
+ * @attr ref android.R.styleable#View_scrollbarThumbHorizontal
+ *
+ * @see #awakenScrollBars(int)
+ * @see #isHorizontalScrollBarEnabled()
+ * @see #setHorizontalScrollBarEnabled(boolean)
+ */
+ public void setHorizontalScrollbarThumbDrawable(@Nullable Drawable drawable) {
+ initializeScrollBarDrawable();
+ mScrollCache.scrollBar.setHorizontalThumbDrawable(drawable);
+ }
+
+ /**
+ * Defines the horizontal track drawable
+ * @attr ref android.R.styleable#View_scrollbarTrackHorizontal
+ *
+ * @see #awakenScrollBars(int)
+ * @see #isHorizontalScrollBarEnabled()
+ * @see #setHorizontalScrollBarEnabled(boolean)
+ */
+ public void setHorizontalScrollbarTrackDrawable(@Nullable Drawable drawable) {
+ initializeScrollBarDrawable();
+ mScrollCache.scrollBar.setHorizontalTrackDrawable(drawable);
+ }
+
+ /**
+ * Returns the currently configured Drawable for the thumb of the vertical scroll bar if it
+ * exists, null otherwise.
+ *
+ * @see #awakenScrollBars(int)
+ * @see #isVerticalScrollBarEnabled()
+ * @see #setVerticalScrollBarEnabled(boolean)
+ */
+ public @Nullable Drawable getVerticalScrollbarThumbDrawable() {
+ return mScrollCache != null ? mScrollCache.scrollBar.getVerticalThumbDrawable() : null;
+ }
+
+ /**
+ * Returns the currently configured Drawable for the track of the vertical scroll bar if it
+ * exists, null otherwise.
+ *
+ * @see #awakenScrollBars(int)
+ * @see #isVerticalScrollBarEnabled()
+ * @see #setVerticalScrollBarEnabled(boolean)
+ */
+ public @Nullable Drawable getVerticalScrollbarTrackDrawable() {
+ return mScrollCache != null ? mScrollCache.scrollBar.getVerticalTrackDrawable() : null;
+ }
+
+ /**
+ * Returns the currently configured Drawable for the thumb of the horizontal scroll bar if it
+ * exists, null otherwise.
+ *
+ * @see #awakenScrollBars(int)
+ * @see #isHorizontalScrollBarEnabled()
+ * @see #setHorizontalScrollBarEnabled(boolean)
+ */
+ public @Nullable Drawable getHorizontalScrollbarThumbDrawable() {
+ return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalThumbDrawable() : null;
+ }
+
+ /**
+ * Returns the currently configured Drawable for the track of the horizontal scroll bar if it
+ * exists, null otherwise.
+ *
+ * @see #awakenScrollBars(int)
+ * @see #isHorizontalScrollBarEnabled()
+ * @see #setHorizontalScrollBarEnabled(boolean)
+ */
+ public @Nullable Drawable getHorizontalScrollbarTrackDrawable() {
+ return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalTrackDrawable() : null;
+ }
+
private void initializeScrollIndicatorsInternal() {
// Some day maybe we'll break this into top/left/start/etc. and let the
// client control it. Until then, you can have any scroll indicator you
@@ -9350,7 +9487,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* Gets the session used to notify Content Capture events.
*
* @return session explicitly set by {@link #setContentCaptureSession(ContentCaptureSession)},
- * inherited by ancestore, default session or {@code null} if content capture is disabled for
+ * inherited by ancestors, default session or {@code null} if content capture is disabled for
* this view.
*/
@Nullable
@@ -28193,18 +28330,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
View mViewRequestingLayout;
/**
- * Used to track views that need (at least) a partial relayout at their current size
- * during the next traversal.
- */
- List<View> mPartialLayoutViews = new ArrayList<>();
-
- /**
- * Swapped with mPartialLayoutViews during layout to avoid concurrent
- * modification. Lazily assigned during ViewRootImpl layout.
- */
- List<View> mEmptyPartialLayoutViews;
-
- /**
* Used to track the identity of the current drag operation.
*/
IBinder mDragToken;
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 6beae37d6b46..bb29ed6c5339 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -293,12 +293,14 @@ public class ViewConfiguration {
*/
private static final float AMBIGUOUS_GESTURE_MULTIPLIER = 2f;
+ private final boolean mConstructedWithContext;
private final int mEdgeSlop;
private final int mFadingEdgeLength;
private final int mMinimumFlingVelocity;
private final int mMaximumFlingVelocity;
private final int mScrollbarSize;
private final int mTouchSlop;
+ private final int mMinScalingSpan;
private final int mHoverSlop;
private final int mMinScrollbarTouchTarget;
private final int mDoubleTapTouchSlop;
@@ -329,6 +331,7 @@ public class ViewConfiguration {
*/
@Deprecated
public ViewConfiguration() {
+ mConstructedWithContext = false;
mEdgeSlop = EDGE_SLOP;
mFadingEdgeLength = FADING_EDGE_LENGTH;
mMinimumFlingVelocity = MINIMUM_FLING_VELOCITY;
@@ -350,6 +353,10 @@ public class ViewConfiguration {
mHorizontalScrollFactor = HORIZONTAL_SCROLL_FACTOR;
mVerticalScrollFactor = VERTICAL_SCROLL_FACTOR;
mShowMenuShortcutsWhenKeyboardPresent = false;
+
+ // Getter throws if mConstructedWithContext is false so doesn't matter what
+ // this value is.
+ mMinScalingSpan = 0;
}
/**
@@ -363,6 +370,7 @@ public class ViewConfiguration {
* @see android.util.DisplayMetrics
*/
private ViewConfiguration(Context context) {
+ mConstructedWithContext = true;
final Resources res = context.getResources();
final DisplayMetrics metrics = res.getDisplayMetrics();
final Configuration config = res.getConfiguration();
@@ -447,6 +455,8 @@ public class ViewConfiguration {
mShowMenuShortcutsWhenKeyboardPresent = res.getBoolean(
com.android.internal.R.bool.config_showMenuShortcutsWhenKeyboardPresent);
+ mMinScalingSpan = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.config_minScalingSpan);
}
/**
@@ -959,6 +969,26 @@ public class ViewConfiguration {
}
/**
+ * Retrieves the distance in pixels between touches that must be reached for a gesture to be
+ * interpreted as scaling.
+ *
+ * In general, scaling shouldn't start until this distance has been met or surpassed, and
+ * scaling should end when the distance in pixels between touches drops below this distance.
+ *
+ * @return The distance in pixels
+ * @throws IllegalStateException if this method is called on a ViewConfiguration that was
+ * instantiated using a constructor with no Context parameter.
+ */
+ public int getScaledMinScalingSpan() {
+ if (!mConstructedWithContext) {
+ throw new IllegalStateException("Min scaling span cannot be determined when this "
+ + "method is called on a ViewConfiguration that was instantiated using a "
+ + "constructor with no Context parameter");
+ }
+ return mMinScalingSpan;
+ }
+
+ /**
* @hide
* @return Whether or not marquee should use fading edges.
*/
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index d2b40f75a6a8..f2474a58b176 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -703,7 +703,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
private void initFromAttributes(
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewGroup, defStyleAttr,
+ final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewGroup,
+ defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.ViewGroup, attrs, a, defStyleAttr,
defStyleRes);
final int N = a.getIndexCount();
@@ -4299,6 +4301,20 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
return i;
}
+ /**
+ * The public version of getChildDrawingOrder().
+ *
+ * Returns the index of the child to draw for this iteration.
+ *
+ * @param i The current iteration.
+ * @return The index of the child to draw this iteration.
+ *
+ * @see #getChildDrawingOrder(int, int)}
+ */
+ public final int getChildDrawingOrder(int i) {
+ return getChildDrawingOrder(getChildCount(), i);
+ }
+
private boolean hasChildWithZ() {
for (int i = 0; i < mChildrenCount; i++) {
if (mChildren[i].getZ() != 0) return true;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1a782ee5d3dd..b1fee2d17079 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3404,21 +3404,25 @@ public final class ViewRootImpl implements ViewParent,
.captureFrameCommitCallbacks();
if (mReportNextDraw) {
usingAsyncReport = true;
- mAttachInfo.mThreadedRenderer.setFrameCompleteCallback((long frameNr) -> {
- // TODO: Use the frame number
- pendingDrawFinished();
- if (commitCallbacks != null) {
- for (int i = 0; i < commitCallbacks.size(); i++) {
- commitCallbacks.get(i).run();
- }
- }
- });
+ final Handler handler = mAttachInfo.mHandler;
+ mAttachInfo.mThreadedRenderer.setFrameCompleteCallback((long frameNr) ->
+ handler.post(() -> {
+ // TODO: Use the frame number
+ pendingDrawFinished();
+ if (commitCallbacks != null) {
+ for (int i = 0; i < commitCallbacks.size(); i++) {
+ commitCallbacks.get(i).run();
+ }
+ }
+ }));
} else if (commitCallbacks != null && commitCallbacks.size() > 0) {
- mAttachInfo.mThreadedRenderer.setFrameCompleteCallback((long frameNr) -> {
- for (int i = 0; i < commitCallbacks.size(); i++) {
- commitCallbacks.get(i).run();
- }
- });
+ final Handler handler = mAttachInfo.mHandler;
+ mAttachInfo.mThreadedRenderer.setFrameCompleteCallback((long frameNr) ->
+ handler.post(() -> {
+ for (int i = 0; i < commitCallbacks.size(); i++) {
+ commitCallbacks.get(i).run();
+ }
+ }));
}
}
diff --git a/core/java/android/view/ViewStub.java b/core/java/android/view/ViewStub.java
index e9d1b8784914..9ca16327844c 100644
--- a/core/java/android/view/ViewStub.java
+++ b/core/java/android/view/ViewStub.java
@@ -108,6 +108,9 @@ public final class ViewStub extends View {
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.ViewStub, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.ViewStub, attrs, a, defStyleAttr,
+ defStyleRes);
+
mInflatedId = a.getResourceId(R.styleable.ViewStub_inflatedId, NO_ID);
mLayoutResource = a.getResourceId(R.styleable.ViewStub_layout, 0);
mID = a.getResourceId(R.styleable.ViewStub_id, NO_ID);
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 46aea80efe7a..e3833c01eeaf 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -520,7 +520,7 @@ public final class WindowManagerGlobal {
return false;
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public void trimMemory(int level) {
if (ThreadedRenderer.isAvailable()) {
if (shouldDestroyEglContext(level)) {
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 06207a9290d7..384cdbb3831c 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -174,7 +174,7 @@ public final class AccessibilityManager {
final Handler.Callback mCallback;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
boolean mIsEnabled;
int mRelevantEventTypes = AccessibilityEvent.TYPES_ALL_MASK;
diff --git a/core/java/android/view/accessibility/OWNERS b/core/java/android/view/accessibility/OWNERS
new file mode 100644
index 000000000000..265674a74b7e
--- /dev/null
+++ b/core/java/android/view/accessibility/OWNERS
@@ -0,0 +1,3 @@
+svetoslavganov@google.com
+pweaver@google.com
+rhedjao@google.com
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index dfd9a2e95cb7..e0950948afb8 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -23,6 +23,7 @@ import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.RectF;
+import android.os.Build;
import android.os.Handler;
import android.os.SystemProperties;
import android.util.AttributeSet;
@@ -30,9 +31,6 @@ import android.util.TypedValue;
import dalvik.system.CloseGuard;
-import java.util.ArrayList;
-import java.util.List;
-
/**
* Abstraction for an Animation that can be applied to Views, Surfaces, or
* other objects. See the {@link android.view.animation animation package
@@ -187,15 +185,12 @@ public abstract class Animation implements Cloneable {
/**
* An animation listener to be notified when the animation starts, ends or repeats.
*/
- @UnsupportedAppUsage
+ // If you need to chain the AnimationListener, wrap the existing Animation into an AnimationSet
+ // and add your new listener to that set
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 117519981)
private AnimationListener mListener;
/**
- * A list of animation listeners to be notified when the animation starts, ends or repeats.
- */
- private List<AnimationListener> mListeners;
-
- /**
* Desired Z order mode during animation.
*/
private int mZAdjustment;
@@ -833,7 +828,7 @@ public abstract class Animation implements Cloneable {
}
private boolean hasAnimationListener() {
- return mListener != null || (mListeners != null && !mListeners.isEmpty());
+ return mListener != null;
}
/**
@@ -848,32 +843,6 @@ public abstract class Animation implements Cloneable {
}
/**
- * <p>Adds an animation listener to this animation. The animation listener
- * is notified of animation events such as the end of the animation or the
- * repetition of the animation.</p>
- *
- * @param listener the animation listener to be notified
- */
- public void addAnimationListener(AnimationListener listener) {
- if (mListeners == null) {
- mListeners = new ArrayList<>(1);
- }
- mListeners.add(listener);
- }
-
- /**
- * <p>Removes an animation listener that has been added with
- * {@link #addAnimationListener(AnimationListener)}.</p>
- *
- * @param listener the animation listener to be removed
- */
- public void removeAnimationListener(AnimationListener listener) {
- if (mListeners != null) {
- mListeners.remove(listener);
- }
- }
-
- /**
* Gurantees that this animation has an interpolator. Will use
* a AccelerateDecelerateInterpolator is nothing else was specified.
*/
@@ -1003,33 +972,18 @@ public abstract class Animation implements Cloneable {
if (mListener != null) {
mListener.onAnimationStart(this);
}
- if (mListeners != null && !mListeners.isEmpty()) {
- for (AnimationListener listener : mListeners) {
- listener.onAnimationStart(this);
- }
- }
}
void dispatchAnimationRepeat() {
if (mListener != null) {
mListener.onAnimationRepeat(this);
}
- if (mListeners != null && !mListeners.isEmpty()) {
- for (AnimationListener listener : mListeners) {
- listener.onAnimationRepeat(this);
- }
- }
}
void dispatchAnimationEnd() {
if (mListener != null) {
mListener.onAnimationEnd(this);
}
- if (mListeners != null && !mListeners.isEmpty()) {
- for (AnimationListener listener : mListeners) {
- listener.onAnimationEnd(this);
- }
- }
}
/**
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 83fc017373a6..f93ac4ce7d16 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -17,7 +17,6 @@
package android.view.autofill;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
-import static android.util.DebugUtils.flagsToString;
import static android.view.autofill.Helper.sDebug;
import static android.view.autofill.Helper.sVerbose;
@@ -338,6 +337,14 @@ public final class AutofillManager {
public static final int MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
/**
+ * Disables Augmented Autofill.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final int FLAG_SMART_SUGGESTION_OFF = 0x0;
+
+ /**
* Displays the Augment Autofill window using the same mechanism (such as a popup-window
* attached to the focused view) as the standard autofill.
*
@@ -347,13 +354,21 @@ public final class AutofillManager {
public static final int FLAG_SMART_SUGGESTION_SYSTEM = 0x1;
/** @hide */
- @IntDef(flag = true, prefix = { "FLAG_SMART_SUGGESTION_" }, value = {
- FLAG_SMART_SUGGESTION_SYSTEM
- })
+ @IntDef(flag = false, value = { FLAG_SMART_SUGGESTION_OFF, FLAG_SMART_SUGGESTION_SYSTEM })
@Retention(RetentionPolicy.SOURCE)
public @interface SmartSuggestionMode {}
/**
+ * {@code DeviceConfig} property used to set which Smart Suggestion modes for Augmented Autofill
+ * are available.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES =
+ "smart_suggestion_supported_modes";
+
+ /**
* Makes an authentication id from a request id and a dataset id.
*
* @param requestId The request id.
@@ -1767,10 +1782,6 @@ public final class AutofillManager {
/**
* Explicitly limits augmented autofill to the given packages and activities.
*
- * <p>When the whitelist is set, it overrides the values passed to
- * {@link #setActivityAugmentedAutofillEnabled(ComponentName, boolean)}
- * and {@link #setPackageAugmentedAutofillEnabled(String, boolean)}.
- *
* <p>To reset the whitelist, call it passing {@code null} to both arguments.
*
* <p>Useful when the service wants to restrict augmented autofill to a category of apps, like
@@ -1788,8 +1799,6 @@ public final class AutofillManager {
*/
@SystemApi
@TestApi
- //TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
- //in the same package as the test, and that module is compiled with SDK=test_current
public void setAugmentedAutofillWhitelist(@Nullable List<String> packages,
@Nullable List<ComponentName> activities) {
// TODO(b/123100824): implement
@@ -2347,7 +2356,14 @@ public final class AutofillManager {
/** @hide */
public static String getSmartSuggestionModeToString(@SmartSuggestionMode int flags) {
- return flagsToString(AutofillManager.class, "FLAG_SMART_SUGGESTION_", flags);
+ switch (flags) {
+ case FLAG_SMART_SUGGESTION_OFF:
+ return "OFF";
+ case FLAG_SMART_SUGGESTION_SYSTEM:
+ return "SYSTEM";
+ default:
+ return "INVALID:" + flags;
+ }
}
@GuardedBy("mLock")
diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
index acb81e086461..13e8a6584218 100644
--- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
@@ -20,10 +20,6 @@ import android.annotation.Nullable;
import android.view.autofill.AutofillId;
import android.view.contentcapture.ViewNode.ViewStructureImpl;
-import com.android.internal.util.Preconditions;
-
-import java.io.PrintWriter;
-
/**
* A session that is explicitly created by the app (and hence is a descendant of
* {@link MainContentCaptureSession}).
@@ -35,21 +31,11 @@ final class ChildContentCaptureSession extends ContentCaptureSession {
@NonNull
private final ContentCaptureSession mParent;
- /**
- * {@link ContentCaptureContext} set by client, or {@code null} when it's the
- * {@link ContentCaptureManager#getMainContentCaptureSession() default session} for the
- * context.
- *
- * @hide
- */
- @NonNull
- private final ContentCaptureContext mClientContext;
-
/** @hide */
protected ChildContentCaptureSession(@NonNull ContentCaptureSession parent,
@NonNull ContentCaptureContext clientContext) {
+ super(clientContext);
mParent = parent;
- mClientContext = Preconditions.checkNotNull(clientContext);
}
@Override
@@ -73,6 +59,11 @@ final class ChildContentCaptureSession extends ContentCaptureSession {
}
@Override
+ public void updateContentCaptureContext(@Nullable ContentCaptureContext context) {
+ getMainCaptureSession().notifyContextUpdated(mId, context);
+ }
+
+ @Override
void onDestroy() {
getMainCaptureSession().notifyChildSessionFinished(mParent.mId, mId);
}
@@ -101,13 +92,4 @@ final class ChildContentCaptureSession extends ContentCaptureSession {
boolean isContentCaptureEnabled() {
return getMainCaptureSession().isContentCaptureEnabled();
}
-
- @Override
- void dump(String prefix, PrintWriter pw) {
- if (mClientContext != null) {
- // NOTE: we don't dump clientContent because it could have PII
- pw.print(prefix); pw.println("hasClientContext");
- }
- super.dump(prefix, pw);
- }
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index 22254cd94059..9cdbefac3d1d 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -91,13 +91,22 @@ public final class ContentCaptureEvent implements Parcelable {
*/
public static final int TYPE_INITIAL_VIEW_TREE_APPEARED = 5;
+ /**
+ * Called after a call to
+ * {@link ContentCaptureSession#setContentCaptureContext(ContentCaptureContext)}.
+ *
+ * <p>The passed context is available through {@link #getContentCaptureContext()}.
+ */
+ public static final int TYPE_CONTEXT_UPDATED = 6;
+
/** @hide */
@IntDef(prefix = { "TYPE_" }, value = {
TYPE_VIEW_APPEARED,
TYPE_VIEW_DISAPPEARED,
TYPE_VIEW_TEXT_CHANGED,
TYPE_INITIAL_VIEW_TREE_APPEARING,
- TYPE_INITIAL_VIEW_TREE_APPEARED
+ TYPE_INITIAL_VIEW_TREE_APPEARED,
+ TYPE_CONTEXT_UPDATED
})
@Retention(RetentionPolicy.SOURCE)
public @interface EventType{}
@@ -193,12 +202,13 @@ public final class ContentCaptureEvent implements Parcelable {
}
/**
- * Used by {@link #TYPE_SESSION_STARTED}.
+ * Gets the {@link ContentCaptureContext} set calls to
+ * {@link ContentCaptureSession#setContentCaptureContext(ContentCaptureContext)}.
*
- * @hide
+ * <p>Only set on {@link #TYPE_CONTEXT_UPDATED} events.
*/
@Nullable
- public ContentCaptureContext getClientContext() {
+ public ContentCaptureContext getContentCaptureContext() {
return mClientContext;
}
@@ -220,8 +230,8 @@ public final class ContentCaptureEvent implements Parcelable {
* Gets the type of the event.
*
* @return one of {@link #TYPE_VIEW_APPEARED}, {@link #TYPE_VIEW_DISAPPEARED},
- * {@link #TYPE_VIEW_TEXT_CHANGED}, {@link #TYPE_INITIAL_VIEW_TREE_APPEARING}, or
- * {@link #TYPE_INITIAL_VIEW_TREE_APPEARED}.
+ * {@link #TYPE_VIEW_TEXT_CHANGED}, {@link #TYPE_INITIAL_VIEW_TREE_APPEARING},
+ * {@link #TYPE_INITIAL_VIEW_TREE_APPEARED}, or {@link #TYPE_CONTEXT_UPDATED}.
*/
public @EventType int getType() {
return mType;
@@ -299,6 +309,10 @@ public final class ContentCaptureEvent implements Parcelable {
if (mText != null) {
pw.print(", text="); pw.println(getSanitizedString(mText));
}
+ if (mClientContext != null) {
+ pw.print(", context="); mClientContext.dump(pw); pw.println();
+
+ }
}
@Override
@@ -325,6 +339,9 @@ public final class ContentCaptureEvent implements Parcelable {
if (mText != null) {
string.append(", text=").append(getSanitizedString(mText));
}
+ if (mClientContext != null) {
+ string.append(", context=").append(mClientContext);
+ }
return string.append(']').toString();
}
@@ -345,7 +362,7 @@ public final class ContentCaptureEvent implements Parcelable {
if (mType == TYPE_SESSION_STARTED || mType == TYPE_SESSION_FINISHED) {
parcel.writeString(mParentSessionId);
}
- if (mType == TYPE_SESSION_STARTED) {
+ if (mType == TYPE_SESSION_STARTED || mType == TYPE_CONTEXT_UPDATED) {
parcel.writeParcelable(mClientContext, flags);
}
}
@@ -375,7 +392,7 @@ public final class ContentCaptureEvent implements Parcelable {
if (type == TYPE_SESSION_STARTED || type == TYPE_SESSION_FINISHED) {
event.setParentSessionId(parcel.readString());
}
- if (type == TYPE_SESSION_STARTED) {
+ if (type == TYPE_SESSION_STARTED || type == TYPE_CONTEXT_UPDATED) {
event.setClientContext(parcel.readParcelable(null));
}
return event;
@@ -404,6 +421,8 @@ public final class ContentCaptureEvent implements Parcelable {
return "INITIAL_VIEW_HIERARCHY_STARTED";
case TYPE_INITIAL_VIEW_TREE_APPEARED:
return "INITIAL_VIEW_HIERARCHY_FINISHED";
+ case TYPE_CONTEXT_UPDATED:
+ return "CONTEXT_UPDATED";
default:
return "UKNOWN_TYPE: " + type;
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 2512b95fe0ec..634443d78b49 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -66,6 +66,25 @@ public final class ContentCaptureManager {
*/
private static final int SYNC_CALLS_TIMEOUT_MS = 5000;
+ /**
+ * DeviceConfig property used by {@code com.android.server.SystemServer} on start to decide
+ * whether the Content Capture service should be created or not
+ *
+ * <p>By default it should *NOT* be set (or set to {@code "default"}, so the decision is based
+ * on whether the OEM provides an implementation for the service), but it can be overridden to:
+ *
+ * <ul>
+ * <li>Provide a "kill switch" so OEMs can disable it remotely in case of emergency (when
+ * it's set to {@code "false"}).
+ * <li>Enable the CTS tests to be run on AOSP builds (when it's set to {@code "true"}).
+ * </ul>
+ *
+ * @hide
+ */
+ @TestApi
+ public static final String DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED =
+ "service_explicitly_enabled";
+
private final Object mLock = new Object();
@NonNull
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index e028961692f9..b8d3fa6f4404 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -166,6 +166,14 @@ public abstract class ContentCaptureSession implements AutoCloseable {
private ContentCaptureSessionId mContentCaptureSessionId;
/**
+ * {@link ContentCaptureContext} set by client, or {@code null} when it's the
+ * {@link ContentCaptureManager#getMainContentCaptureSession() default session} for the
+ * context.
+ */
+ @Nullable
+ private ContentCaptureContext mClientContext;
+
+ /**
* List of children session.
*/
@Nullable
@@ -183,6 +191,12 @@ public abstract class ContentCaptureSession implements AutoCloseable {
mId = Preconditions.checkNotNull(id);
}
+ // Used by ChildCOntentCaptureSession
+ ContentCaptureSession(@NonNull ContentCaptureContext initialContext) {
+ this();
+ mClientContext = Preconditions.checkNotNull(initialContext);
+ }
+
/** @hide */
@NonNull
abstract MainContentCaptureSession getMainCaptureSession();
@@ -240,6 +254,30 @@ public abstract class ContentCaptureSession implements AutoCloseable {
abstract void flush(@FlushReason int reason);
/**
+ * Sets the {@link ContentCaptureContext} associated with the session.
+ *
+ * <p>Typically used to change the context associated with the default session from an activity.
+ */
+ public final void setContentCaptureContext(@Nullable ContentCaptureContext context) {
+ mClientContext = context;
+ updateContentCaptureContext(context);
+ }
+
+ abstract void updateContentCaptureContext(@Nullable ContentCaptureContext context);
+
+ /**
+ * Gets the {@link ContentCaptureContext} associated with the session.
+ *
+ * @return context set on constructor or by
+ * {@link #setContentCaptureContext(ContentCaptureContext)}, or {@code null} if never
+ * explicitly set.
+ */
+ @Nullable
+ public final ContentCaptureContext getContentCaptureContext() {
+ return mClientContext;
+ }
+
+ /**
* Destroys this session, flushing out all pending notifications to the service.
*
* <p>Once destroyed, any new notification will be dropped.
@@ -424,6 +462,9 @@ public abstract class ContentCaptureSession implements AutoCloseable {
@CallSuper
void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
pw.print(prefix); pw.print("id: "); pw.println(mId);
+ if (mClientContext != null) {
+ pw.print(prefix); mClientContext.dump(pw); pw.println();
+ }
synchronized (mLock) {
pw.print(prefix); pw.print("destroyed: "); pw.println(mDestroyed);
if (mChildren != null && !mChildren.isEmpty()) {
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 810c967ce2c8..d949f45ba5e6 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -15,6 +15,7 @@
*/
package android.view.contentcapture;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_CONTEXT_UPDATED;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_INITIAL_VIEW_TREE_APPEARED;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_INITIAL_VIEW_TREE_APPEARING;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_FINISHED;
@@ -269,11 +270,12 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
private void sendEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) {
final int eventType = event.getType();
if (VERBOSE) Log.v(TAG, "handleSendEvent(" + getDebugState() + "): " + event);
- if (!hasStarted() && eventType != ContentCaptureEvent.TYPE_SESSION_STARTED) {
+ if (!hasStarted() && eventType != ContentCaptureEvent.TYPE_SESSION_STARTED
+ && eventType != ContentCaptureEvent.TYPE_CONTEXT_UPDATED) {
// TODO(b/120494182): comment when this could happen (dialogs?)
Log.v(TAG, "handleSendEvent(" + getDebugState() + ", "
+ ContentCaptureEvent.getTypeAsString(eventType)
- + "): session not started yet");
+ + "): dropping because session not started yet");
return;
}
if (mDisabled.get()) {
@@ -476,6 +478,11 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
}
}
+ @Override
+ public void updateContentCaptureContext(@Nullable ContentCaptureContext context) {
+ notifyContextUpdated(mId, context);
+ }
+
/**
* Resets the buffer and return a {@link ParceledListSlice} with the previous events.
*/
@@ -613,6 +620,12 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
}
}
+ void notifyContextUpdated(@NonNull String sessionId,
+ @Nullable ContentCaptureContext context) {
+ sendEvent(new ContentCaptureEvent(sessionId, TYPE_CONTEXT_UPDATED)
+ .setClientContext(context));
+ }
+
@Override
void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
pw.print(prefix); pw.print("mContext: "); pw.println(mContext);
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 8a097883dd5c..e63a406411d8 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1373,7 +1373,7 @@ public final class InputMethodManager {
* @hide
*/
@Deprecated
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768499)
public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) {
try {
Log.w(TAG, "showSoftInputUnchecked() is a hidden method, which will be removed "
diff --git a/core/java/android/view/textclassifier/ConversationAction.java b/core/java/android/view/textclassifier/ConversationAction.java
index 1a6e5d8e8b03..ae6a645c90a1 100644
--- a/core/java/android/view/textclassifier/ConversationAction.java
+++ b/core/java/android/view/textclassifier/ConversationAction.java
@@ -92,6 +92,9 @@ public final class ConversationAction implements Parcelable {
*/
public static final String TYPE_SHARE_LOCATION = "share_location";
+ /** @hide **/
+ public static final String TYPE_ADD_CONTACT = "add_contact";
+
public static final Creator<ConversationAction> CREATOR =
new Creator<ConversationAction>() {
@Override
diff --git a/core/java/android/view/textclassifier/TEST_MAPPING b/core/java/android/view/textclassifier/TEST_MAPPING
new file mode 100644
index 000000000000..01a6edecf21e
--- /dev/null
+++ b/core/java/android/view/textclassifier/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "android.view.textclassifier"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/core/java/android/view/textclassifier/TextClassificationConstants.java b/core/java/android/view/textclassifier/TextClassificationConstants.java
index ee9e04e5329a..2ef8d04939bd 100644
--- a/core/java/android/view/textclassifier/TextClassificationConstants.java
+++ b/core/java/android/view/textclassifier/TextClassificationConstants.java
@@ -131,6 +131,7 @@ public final class TextClassificationConstants {
.add(ConversationAction.TYPE_TRACK_FLIGHT)
.add(ConversationAction.TYPE_VIEW_CALENDAR)
.add(ConversationAction.TYPE_VIEW_MAP)
+ .add(ConversationAction.TYPE_ADD_CONTACT)
.toString();
/**
* < 0 : Not set. Use value from LangId model.
diff --git a/core/java/android/webkit/OWNERS b/core/java/android/webkit/OWNERS
index 00e540a46ab2..b33da57c42e3 100644
--- a/core/java/android/webkit/OWNERS
+++ b/core/java/android/webkit/OWNERS
@@ -1,3 +1,4 @@
changwan@google.com
+ntfschr@google.com
tobiasjs@google.com
torne@google.com
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 60393502bbe7..3555822b1f1f 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -61,6 +61,7 @@ import android.view.accessibility.AccessibilityNodeProvider;
import android.view.autofill.AutofillValue;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
+import android.view.inspector.InspectableProperty;
import android.view.textclassifier.TextClassifier;
import android.widget.AbsoluteLayout;
@@ -759,7 +760,7 @@ public class WebView extends AbsoluteLayout
* <p>
* The {@code encoding} parameter specifies whether the data is base64 or URL
* encoded. If the data is base64 encoded, the value of the encoding
- * parameter must be 'base64'. HTML can be encoded with {@link
+ * parameter must be {@code "base64"}. HTML can be encoded with {@link
* android.util.Base64#encodeToString(byte[],int)} like so:
* <pre>
* String unencodedHtml =
@@ -767,11 +768,15 @@ public class WebView extends AbsoluteLayout
* String encodedHtml = Base64.encodeToString(unencodedHtml.getBytes(), Base64.NO_PADDING);
* webView.loadData(encodedHtml, "text/html", "base64");
* </pre>
- * <p>
+ * <p class="note">
* For all other values of {@code encoding} (including {@code null}) it is assumed that the
* data uses ASCII encoding for octets inside the range of safe URL characters and use the
* standard %xx hex encoding of URLs for octets outside that range. See <a
* href="https://tools.ietf.org/html/rfc3986#section-2.2">RFC 3986</a> for more information.
+ * Applications targeting {@link android.os.Build.VERSION_CODES#Q} or later must either use
+ * base64 or encode any {@code #} characters in the content as {@code %23}, otherwise they
+ * will be treated as the end of the content and the remaining text used as a document
+ * fragment identifier.
* <p>
* The {@code mimeType} parameter specifies the format of the data.
* If WebView can't handle the specified MIME type, it will download the data.
@@ -819,7 +824,8 @@ public class WebView extends AbsoluteLayout
* <p>
* If the base URL uses the data scheme, this method is equivalent to
* calling {@link #loadData(String,String,String) loadData()} and the
- * historyUrl is ignored, and the data will be treated as part of a data: URL.
+ * historyUrl is ignored, and the data will be treated as part of a data: URL,
+ * including the requirement that the content be URL-encoded or base64 encoded.
* If the base URL uses any other scheme, then the data will be loaded into
* the WebView as a plain string (i.e. not part of a data URL) and any URL-encoded
* entities in the string will not be decoded.
@@ -1239,6 +1245,7 @@ public class WebView extends AbsoluteLayout
*
* @return the URL for the current page
*/
+ @InspectableProperty(hasAttributeId = false)
@ViewDebug.ExportedProperty(category = "webview")
public String getUrl() {
checkThread();
@@ -1254,6 +1261,7 @@ public class WebView extends AbsoluteLayout
*
* @return the URL that was originally requested for the current page
*/
+ @InspectableProperty(hasAttributeId = false)
@ViewDebug.ExportedProperty(category = "webview")
public String getOriginalUrl() {
checkThread();
@@ -1266,6 +1274,7 @@ public class WebView extends AbsoluteLayout
*
* @return the title for the current page
*/
+ @InspectableProperty(hasAttributeId = false)
@ViewDebug.ExportedProperty(category = "webview")
public String getTitle() {
checkThread();
@@ -1278,6 +1287,7 @@ public class WebView extends AbsoluteLayout
*
* @return the favicon for the current page
*/
+ @InspectableProperty(hasAttributeId = false)
public Bitmap getFavicon() {
checkThread();
return mProvider.getFavicon();
@@ -1300,6 +1310,7 @@ public class WebView extends AbsoluteLayout
*
* @return the progress for the current page between 0 and 100
*/
+ @InspectableProperty(hasAttributeId = false)
public int getProgress() {
checkThread();
return mProvider.getProgress();
@@ -1310,6 +1321,7 @@ public class WebView extends AbsoluteLayout
*
* @return the height of the HTML content
*/
+ @InspectableProperty(hasAttributeId = false)
@ViewDebug.ExportedProperty(category = "webview")
public int getContentHeight() {
checkThread();
@@ -2276,6 +2288,11 @@ public class WebView extends AbsoluteLayout
*
* @return the requested renderer priority policy.
*/
+ @InspectableProperty(hasAttributeId = false, enumMapping = {
+ @InspectableProperty.EnumMap(name = "waived", value = RENDERER_PRIORITY_WAIVED),
+ @InspectableProperty.EnumMap(name = "bound", value = RENDERER_PRIORITY_BOUND),
+ @InspectableProperty.EnumMap(name = "important", value = RENDERER_PRIORITY_IMPORTANT)
+ })
@RendererPriority
public int getRendererRequestedPriority() {
return mProvider.getRendererRequestedPriority();
@@ -2288,6 +2305,7 @@ public class WebView extends AbsoluteLayout
* @return whether this WebView requests a priority of
* {@link #RENDERER_PRIORITY_WAIVED} when not visible.
*/
+ @InspectableProperty(hasAttributeId = false)
public boolean getRendererPriorityWaivedWhenNotVisible() {
return mProvider.getRendererPriorityWaivedWhenNotVisible();
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 9d7a482aa611..f01babe7b894 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -325,13 +325,13 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
/**
* The current position of the selector in the list.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
int mSelectorPosition = INVALID_POSITION;
/**
* Defines the selector's location and dimension at drawing time
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
Rect mSelectorRect = new Rect();
/**
@@ -657,7 +657,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
private Runnable mClearScrollingCache;
Runnable mPositionScrollAfterLayout;
private int mMinimumVelocity;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124051740)
private int mMaximumVelocity;
private float mVelocityScale = 1.0f;
@@ -875,6 +875,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.AbsListView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.AbsListView, attrs, a, defStyleAttr,
+ defStyleRes);
final Drawable selector = a.getDrawable(R.styleable.AbsListView_listSelector);
if (selector != null) {
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index c8be1d66ed4a..cd5f2e222b39 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -107,6 +107,8 @@ public abstract class AbsSeekBar extends ProgressBar {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.SeekBar, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.SeekBar, attrs, a, defStyleAttr,
+ defStyleRes);
final Drawable thumb = a.getDrawable(R.styleable.SeekBar_thumb);
setThumb(thumb);
diff --git a/core/java/android/widget/AbsSpinner.java b/core/java/android/widget/AbsSpinner.java
index 816c9499e292..3dcba48b8dc8 100644
--- a/core/java/android/widget/AbsSpinner.java
+++ b/core/java/android/widget/AbsSpinner.java
@@ -82,6 +82,8 @@ public abstract class AbsSpinner extends AdapterView<SpinnerAdapter> {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.AbsSpinner, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.AbsSpinner, attrs, a, defStyleAttr,
+ defStyleRes);
final CharSequence[] entries = a.getTextArray(R.styleable.AbsSpinner_entries);
if (entries != null) {
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index 58715eefc25e..89ea0747b532 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -232,6 +232,8 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
TypedArray attributesArray = context.obtainStyledAttributes(attrs,
R.styleable.ActivityChooserView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.ActivityChooserView, attrs,
+ attributesArray, defStyleAttr, defStyleRes);
mInitialActivityCount = attributesArray.getInt(
R.styleable.ActivityChooserView_initialActivityCount,
diff --git a/core/java/android/widget/AdapterViewAnimator.java b/core/java/android/widget/AdapterViewAnimator.java
index 6f293684ad3c..5174c1a34fcd 100644
--- a/core/java/android/widget/AdapterViewAnimator.java
+++ b/core/java/android/widget/AdapterViewAnimator.java
@@ -180,6 +180,9 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
final TypedArray a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.AdapterViewAnimator, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.AdapterViewAnimator,
+ attrs, a, defStyleAttr, defStyleRes);
+
int resource = a.getResourceId(
com.android.internal.R.styleable.AdapterViewAnimator_inAnimation, 0);
if (resource > 0) {
diff --git a/core/java/android/widget/AdapterViewFlipper.java b/core/java/android/widget/AdapterViewFlipper.java
index 18d74705773a..065089f53633 100644
--- a/core/java/android/widget/AdapterViewFlipper.java
+++ b/core/java/android/widget/AdapterViewFlipper.java
@@ -69,6 +69,8 @@ public class AdapterViewFlipper extends AdapterViewAnimator {
final TypedArray a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.AdapterViewFlipper, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.AdapterViewFlipper,
+ attrs, a, defStyleAttr, defStyleRes);
mFlipInterval = a.getInt(
com.android.internal.R.styleable.AdapterViewFlipper_flipInterval, DEFAULT_INTERVAL);
mAutoStart = a.getBoolean(
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 795b03493efb..339947ac8d5a 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -81,6 +81,8 @@ public class AnalogClock extends View {
final Resources r = context.getResources();
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.AnalogClock, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.AnalogClock,
+ attrs, a, defStyleAttr, defStyleRes);
mDial = a.getDrawable(com.android.internal.R.styleable.AnalogClock_dial);
if (mDial == null) {
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 9bc055e7111b..904a86261e6c 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -126,7 +126,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
private boolean mDropDownDismissedOnCompletion = true;
private int mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN;
- private boolean mOpenBefore;
+ private MyWatcher mAutoCompleteTextWatcher;
private Validator mValidator = null;
@@ -227,6 +227,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.AutoCompleteTextView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.AutoCompleteTextView,
+ attrs, a, defStyleAttr, defStyleRes);
if (popupTheme != null) {
mPopupContext = new ContextThemeWrapper(context, popupTheme);
@@ -245,6 +247,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
if (mPopupContext != context) {
pa = mPopupContext.obtainStyledAttributes(
attrs, R.styleable.AutoCompleteTextView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.AutoCompleteTextView,
+ attrs, a, defStyleAttr, defStyleRes);
} else {
pa = a;
}
@@ -302,7 +306,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
setFocusable(true);
- addTextChangedListener(new MyWatcher());
+ mAutoCompleteTextWatcher = new MyWatcher();
+ addTextChangedListener(mAutoCompleteTextWatcher);
mPassThroughClickListener = new PassThroughClickListener();
super.setOnClickListener(mPassThroughClickListener);
@@ -872,45 +877,66 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
return getText().length() >= mThreshold;
}
- /**
- * This is used to watch for edits to the text view. Note that we call
- * to methods on the auto complete text view class so that we can access
- * private vars without going through thunks.
- */
+
+
+ /** This is used to watch for edits to the text view. */
private class MyWatcher implements TextWatcher {
- public void afterTextChanged(Editable s) {
- doAfterTextChanged();
- }
+ private boolean mOpenBefore;
+
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- doBeforeTextChanged();
+ if (mBlockCompletion) return;
+
+ // when text is changed, inserted or deleted, we attempt to show
+ // the drop down
+ mOpenBefore = isPopupShowing();
+ if (DEBUG) Log.v(TAG, "before text changed: open=" + mOpenBefore);
+ }
+
+ public void afterTextChanged(Editable s) {
+ if (mBlockCompletion) return;
+
+ // if the list was open before the keystroke, but closed afterwards,
+ // then something in the keystroke processing (an input filter perhaps)
+ // called performCompletion() and we shouldn't do any more processing.
+ if (DEBUG) {
+ Log.v(TAG, "after text changed: openBefore=" + mOpenBefore
+ + " open=" + isPopupShowing());
+ }
+
+ if (mOpenBefore && !isPopupShowing()) return;
+
+ refreshAutoCompleteResults();
}
+
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
}
- @UnsupportedAppUsage
+ /**
+ * This function is deprecated. Please use {@link #refreshAutoCompleteResults} instead.
+ * Note: Remove {@link #mAutoCompleteTextWatcher} after removing this function.
+ */
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
void doBeforeTextChanged() {
- if (mBlockCompletion) return;
-
- // when text is changed, inserted or deleted, we attempt to show
- // the drop down
- mOpenBefore = isPopupShowing();
- if (DEBUG) Log.v(TAG, "before text changed: open=" + mOpenBefore);
+ mAutoCompleteTextWatcher.beforeTextChanged(null, 0, 0, 0);
}
- @UnsupportedAppUsage
+ /**
+ * This function is deprecated. Please use {@link #refreshAutoCompleteResults} instead.
+ * Note: Remove {@link #mAutoCompleteTextWatcher} after removing this function.
+ */
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
void doAfterTextChanged() {
- if (mBlockCompletion) return;
-
- // if the list was open before the keystroke, but closed afterwards,
- // then something in the keystroke processing (an input filter perhaps)
- // called performCompletion() and we shouldn't do any more processing.
- if (DEBUG) Log.v(TAG, "after text changed: openBefore=" + mOpenBefore
- + " open=" + isPopupShowing());
- if (mOpenBefore && !isPopupShowing()) {
- return;
- }
+ mAutoCompleteTextWatcher.afterTextChanged(null);
+ }
+ /**
+ * Refreshes the auto complete results. You usually shouldn't have to manually refresh the
+ * AutoCompleteResults as this is done automatically whenever the text changes. However if the
+ * results are not available and have to be fetched, you can call this function after fetching
+ * the results.
+ */
+ public final void refreshAutoCompleteResults() {
// the drop down is shown only when a minimum number of characters
// was typed in the text view
if (enoughToFilter()) {
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index 6c74c8c24c44..b552aa6c85c4 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -112,6 +112,8 @@ public class CalendarView extends FrameLayout {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.CalendarView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.CalendarView,
+ attrs, a, defStyleAttr, defStyleRes);
final int mode = a.getInt(R.styleable.CalendarView_calendarViewMode, MODE_HOLO);
a.recycle();
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index b7fdcbe2b399..99440f862871 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -90,6 +90,8 @@ public class CheckedTextView extends TextView implements Checkable {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.CheckedTextView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.CheckedTextView,
+ attrs, a, defStyleAttr, defStyleRes);
final Drawable d = a.getDrawable(R.styleable.CheckedTextView_checkMark);
if (d != null) {
diff --git a/core/java/android/widget/Chronometer.java b/core/java/android/widget/Chronometer.java
index 66c35d903366..0b67cad0112b 100644
--- a/core/java/android/widget/Chronometer.java
+++ b/core/java/android/widget/Chronometer.java
@@ -116,6 +116,8 @@ public class Chronometer extends TextView {
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.Chronometer, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.Chronometer,
+ attrs, a, defStyleAttr, defStyleRes);
setFormat(a.getString(R.styleable.Chronometer_format));
setCountDown(a.getBoolean(R.styleable.Chronometer_countDown, false));
a.recycle();
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index a0f93da90847..3cfd373c2906 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -100,6 +100,8 @@ public abstract class CompoundButton extends Button implements Checkable {
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.CompoundButton, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.CompoundButton,
+ attrs, a, defStyleAttr, defStyleRes);
final Drawable d = a.getDrawable(com.android.internal.R.styleable.CompoundButton_button);
if (d != null) {
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index cca951ca9298..ada4f00256eb 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -161,6 +161,8 @@ public class DatePicker extends FrameLayout {
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePicker,
defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.DatePicker,
+ attrs, a, defStyleAttr, defStyleRes);
final boolean isDialogMode = a.getBoolean(R.styleable.DatePicker_dialogMode, false);
final int requestedMode = a.getInt(R.styleable.DatePicker_datePickerMode, MODE_SPINNER);
final int firstDayOfWeek = a.getInt(R.styleable.DatePicker_firstDayOfWeek, 0);
diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java
index f712d5fa65ca..67fef13d23f2 100644
--- a/core/java/android/widget/DayPickerView.java
+++ b/core/java/android/widget/DayPickerView.java
@@ -82,6 +82,8 @@ class DayPickerView extends ViewGroup {
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.CalendarView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.CalendarView,
+ attrs, a, defStyleAttr, defStyleRes);
final int firstDayOfWeek = a.getInt(R.styleable.CalendarView_firstDayOfWeek,
LocaleData.get(Locale.getDefault()).firstDayOfWeek);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 9c21ba60a034..ded3be4e4ef5 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -6020,9 +6020,6 @@ public class Editor {
}
updateSelection(event);
- if (mTextView.hasSelection() && mEndHandle != null) {
- mEndHandle.updateMagnifier(event);
- }
break;
case MotionEvent.ACTION_UP:
@@ -6030,9 +6027,6 @@ public class Editor {
break;
}
updateSelection(event);
- if (mEndHandle != null) {
- mEndHandle.dismissMagnifier();
- }
// No longer dragging to select text, let the parent intercept events.
mTextView.getParent().requestDisallowInterceptTouchEvent(false);
diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java
index 33d15394332e..2cc013ec4f78 100644
--- a/core/java/android/widget/ExpandableListView.java
+++ b/core/java/android/widget/ExpandableListView.java
@@ -242,6 +242,8 @@ public class ExpandableListView extends ListView {
final TypedArray a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.ExpandableListView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.ExpandableListView,
+ attrs, a, defStyleAttr, defStyleRes);
mGroupIndicator = a.getDrawable(
com.android.internal.R.styleable.ExpandableListView_groupIndicator);
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 5723b9467aa2..3570c79430a4 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -100,6 +100,8 @@ public class FrameLayout extends ViewGroup {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.FrameLayout, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.FrameLayout,
+ attrs, a, defStyleAttr, defStyleRes);
if (a.getBoolean(R.styleable.FrameLayout_measureAllChildren, false)) {
setMeasureAllChildren(true);
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index d6a0ae48cc13..64192aaff1cf 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -213,6 +213,8 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.Gallery, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.Gallery,
+ attrs, a, defStyleAttr, defStyleRes);
int index = a.getInt(com.android.internal.R.styleable.Gallery_gravity, -1);
if (index >= 0) {
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index c8abf18f88f9..1c8bb0470e2e 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -303,6 +303,8 @@ public class GridLayout extends ViewGroup {
mDefaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap);
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.GridLayout, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.GridLayout,
+ attrs, a, defStyleAttr, defStyleRes);
try {
setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT));
setColumnCount(a.getInt(COLUMN_COUNT, DEFAULT_COUNT));
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index bbbe369d5262..a6129b04d14f 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -150,6 +150,8 @@ public class GridView extends AbsListView {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.GridView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.GridView,
+ attrs, a, defStyleAttr, defStyleRes);
int hSpacing = a.getDimensionPixelOffset(
R.styleable.GridView_horizontalSpacing, 0);
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 1c5f837728a0..25cfdc7e4411 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -80,10 +81,24 @@ public class HorizontalScrollView extends FrameLayout {
private final Rect mTempRect = new Rect();
@UnsupportedAppUsage
private OverScroller mScroller;
- @UnsupportedAppUsage
- private EdgeEffect mEdgeGlowLeft;
- @UnsupportedAppUsage
- private EdgeEffect mEdgeGlowRight;
+ /**
+ * Tracks the state of the left edge glow.
+ *
+ * Even though this field is practically final, we cannot make it final because there are apps
+ * setting it via reflection and they need to keep working until they target Q.
+ */
+ @NonNull
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124053130)
+ private EdgeEffect mEdgeGlowLeft = new EdgeEffect(getContext());
+
+ /**
+ * Tracks the state of the bottom edge glow.
+ *
+ * Even though this field is practically final, we cannot make it final because there are apps
+ * setting it via reflection and they need to keep working until they target Q.
+ */
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124052619)
+ private EdgeEffect mEdgeGlowRight = new EdgeEffect(getContext());
/**
* Position of the last motion event.
@@ -175,6 +190,8 @@ public class HorizontalScrollView extends FrameLayout {
final TypedArray a = context.obtainStyledAttributes(
attrs, android.R.styleable.HorizontalScrollView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, android.R.styleable.HorizontalScrollView,
+ attrs, a, defStyleAttr, defStyleRes);
setFillViewport(a.getBoolean(android.R.styleable.HorizontalScrollView_fillViewport, false));
@@ -216,6 +233,74 @@ public class HorizontalScrollView extends FrameLayout {
}
/**
+ * Sets the edge effect color for both left and right edge effects.
+ *
+ * @param color The color for the edge effects.
+ * @see #setLeftEdgeEffectColor(int)
+ * @see #setRightEdgeEffectColor(int)
+ * @see #getLeftEdgeEffectColor()
+ * @see #getRightEdgeEffectColor()
+ */
+ public void setEdgeEffectColor(@ColorInt int color) {
+ setLeftEdgeEffectColor(color);
+ setRightEdgeEffectColor(color);
+ }
+
+ /**
+ * Sets the right edge effect color.
+ *
+ * @param color The color for the right edge effect.
+ * @see #setLeftEdgeEffectColor(int)
+ * @see #setEdgeEffectColor(int)
+ * @see #getLeftEdgeEffectColor()
+ * @see #getRightEdgeEffectColor()
+ */
+ public void setRightEdgeEffectColor(@ColorInt int color) {
+ mEdgeGlowRight.setColor(color);
+ }
+
+ /**
+ * Sets the left edge effect color.
+ *
+ * @param color The color for the left edge effect.
+ * @see #setRightEdgeEffectColor(int)
+ * @see #setEdgeEffectColor(int)
+ * @see #getLeftEdgeEffectColor()
+ * @see #getRightEdgeEffectColor()
+ */
+ public void setLeftEdgeEffectColor(@ColorInt int color) {
+ mEdgeGlowLeft.setColor(color);
+ }
+
+ /**
+ * Returns the left edge effect color.
+ *
+ * @return The left edge effect color.
+ * @see #setEdgeEffectColor(int)
+ * @see #setLeftEdgeEffectColor(int)
+ * @see #setRightEdgeEffectColor(int)
+ * @see #getRightEdgeEffectColor()
+ */
+ @ColorInt
+ public int getLeftEdgeEffectColor() {
+ return mEdgeGlowLeft.getColor();
+ }
+
+ /**
+ * Returns the right edge effect color.
+ *
+ * @return The right edge effect color.
+ * @see #setEdgeEffectColor(int)
+ * @see #setLeftEdgeEffectColor(int)
+ * @see #setRightEdgeEffectColor(int)
+ * @see #getLeftEdgeEffectColor()
+ */
+ @ColorInt
+ public int getRightEdgeEffectColor() {
+ return mEdgeGlowRight.getColor();
+ }
+
+ /**
* @return The maximum amount this scroll view will scroll in response to
* an arrow event.
*/
@@ -665,7 +750,7 @@ public class HorizontalScrollView extends FrameLayout {
mEdgeGlowLeft.onRelease();
}
}
- if (mEdgeGlowLeft != null
+ if (shouldDisplayEdgeEffects()
&& (!mEdgeGlowLeft.isFinished() || !mEdgeGlowRight.isFinished())) {
postInvalidateOnAnimation();
}
@@ -693,7 +778,7 @@ public class HorizontalScrollView extends FrameLayout {
mIsBeingDragged = false;
recycleVelocityTracker();
- if (mEdgeGlowLeft != null) {
+ if (shouldDisplayEdgeEffects()) {
mEdgeGlowLeft.onRelease();
mEdgeGlowRight.onRelease();
}
@@ -708,7 +793,7 @@ public class HorizontalScrollView extends FrameLayout {
mIsBeingDragged = false;
recycleVelocityTracker();
- if (mEdgeGlowLeft != null) {
+ if (shouldDisplayEdgeEffects()) {
mEdgeGlowLeft.onRelease();
mEdgeGlowRight.onRelease();
}
@@ -1650,26 +1735,15 @@ public class HorizontalScrollView extends FrameLayout {
}
}
- @Override
- public void setOverScrollMode(int mode) {
- if (mode != OVER_SCROLL_NEVER) {
- if (mEdgeGlowLeft == null) {
- Context context = getContext();
- mEdgeGlowLeft = new EdgeEffect(context);
- mEdgeGlowRight = new EdgeEffect(context);
- }
- } else {
- mEdgeGlowLeft = null;
- mEdgeGlowRight = null;
- }
- super.setOverScrollMode(mode);
+ private boolean shouldDisplayEdgeEffects() {
+ return getOverScrollMode() != OVER_SCROLL_NEVER;
}
@SuppressWarnings({"SuspiciousNameCombination"})
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
- if (mEdgeGlowLeft != null) {
+ if (shouldDisplayEdgeEffects()) {
final int scrollX = mScrollX;
if (!mEdgeGlowLeft.isFinished()) {
final int restoreCount = canvas.save();
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index e9c31db8110b..9ae62ef8ab7a 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -138,7 +138,7 @@ public class ImageView extends View {
private int mDrawableWidth;
@UnsupportedAppUsage
private int mDrawableHeight;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124051687)
private Matrix mDrawMatrix = null;
// Avoid allocations...
@@ -200,6 +200,8 @@ public class ImageView extends View {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.ImageView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.ImageView,
+ attrs, a, defStyleAttr, defStyleRes);
final Drawable d = a.getDrawable(R.styleable.ImageView_src);
if (d != null) {
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 64769b5337df..e833df9d498a 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -264,6 +264,8 @@ public class LinearLayout extends ViewGroup {
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.LinearLayout, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.LinearLayout,
+ attrs, a, defStyleAttr, defStyleRes);
int index = a.getInt(com.android.internal.R.styleable.LinearLayout_orientation, -1);
if (index >= 0) {
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index f9564b44e825..25e5dd32c6b2 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -471,11 +471,24 @@ public class ListPopupWindow implements ShowableListMenu {
* Specifies the anchor-relative bounds of the popup's transition
* epicenter.
*
- * @param bounds anchor-relative bounds
- * @hide
+ * @param bounds anchor-relative bounds, or {@code null} to use default epicenter
+ *
+ * @see #getEpicenterBounds()
+ */
+ public void setEpicenterBounds(@Nullable Rect bounds) {
+ mEpicenterBounds = bounds != null ? new Rect(bounds) : null;
+ }
+
+ /**
+ * Returns bounds which are used as a popup's epicenter
+ * of the enter and exit transitions.
+ *
+ * @return bounds relative to anchor view, or {@code null} if not set
+ * @see #setEpicenterBounds(Rect)
*/
- public void setEpicenterBounds(Rect bounds) {
- mEpicenterBounds = bounds;
+ @Nullable
+ public Rect getEpicenterBounds() {
+ return mEpicenterBounds != null ? new Rect(mEpicenterBounds) : null;
}
/**
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 311f8968150c..2aa019b5d0f4 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -236,6 +236,8 @@ public class ListView extends AbsListView {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.ListView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.ListView,
+ attrs, a, defStyleAttr, defStyleRes);
final CharSequence[] entries = a.getTextArray(R.styleable.ListView_entries);
if (entries != null) {
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 157992a98a4a..dad2669d3de8 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -17,6 +17,8 @@
package android.widget;
import android.annotation.CallSuper;
+import android.annotation.ColorInt;
+import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.Px;
@@ -340,7 +342,7 @@ public class NumberPicker extends LinearLayout {
/**
* The {@link Paint} for drawing the selector.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private final Paint mSelectorWheelPaint;
/**
@@ -639,6 +641,8 @@ public class NumberPicker extends LinearLayout {
// process style attributes
final TypedArray attributesArray = context.obtainStyledAttributes(
attrs, R.styleable.NumberPicker, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.NumberPicker,
+ attrs, attributesArray, defStyleAttr, defStyleRes);
final int layoutResId = attributesArray.getResourceId(
R.styleable.NumberPicker_internalLayout, DEFAULT_LAYOUT_RESOURCE_ID);
@@ -1716,6 +1720,44 @@ public class NumberPicker extends LinearLayout {
}
/**
+ * Sets the text color for all the states (normal, selected, focused) to be the given color.
+ *
+ * @param color A color value in the form 0xAARRGGBB.
+ */
+ public void setTextColor(@ColorInt int color) {
+ mSelectorWheelPaint.setColor(color);
+ mInputText.setTextColor(color);
+ invalidate();
+ }
+
+ /**
+ * @return the text color.
+ */
+ @ColorInt
+ public int getTextColor() {
+ return mSelectorWheelPaint.getColor();
+ }
+
+ /**
+ * Sets the text size to the given value. This value must be > 0
+ *
+ * @param size The size in pixel units.
+ */
+ public void setTextSize(@FloatRange(from = 0.0, fromInclusive = false) float size) {
+ mSelectorWheelPaint.setTextSize(size);
+ mInputText.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
+ invalidate();
+ }
+
+ /**
+ * @return the size (in pixels) of the text size in this NumberPicker.
+ */
+ @FloatRange(from = 0.0, fromInclusive = false)
+ public float getTextSize() {
+ return mSelectorWheelPaint.getTextSize();
+ }
+
+ /**
* Makes a measure spec that tries greedily to use the max value.
*
* @param measureSpec The measure spec.
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 88d938082b05..279829672c57 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -490,7 +490,7 @@ public class PopupWindow {
*/
@Nullable
public Rect getEpicenterBounds() {
- return mEpicenterBounds;
+ return mEpicenterBounds != null ? new Rect(mEpicenterBounds) : null;
}
/**
@@ -509,7 +509,7 @@ public class PopupWindow {
* @see #getEpicenterBounds()
*/
public void setEpicenterBounds(@Nullable Rect bounds) {
- mEpicenterBounds = bounds;
+ mEpicenterBounds = bounds != null ? new Rect(bounds) : null;
}
private Transition getTransition(int resId) {
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 6b48c6584ad2..29f070ed5a65 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -203,7 +203,7 @@ public class ProgressBar extends View {
private int mDuration;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private boolean mIndeterminate;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(trackingBug = 124049927)
private boolean mOnlyIndeterminate;
private Transformation mTransformation;
private AlphaAnimation mAnimation;
@@ -211,7 +211,12 @@ public class ProgressBar extends View {
private Drawable mIndeterminateDrawable;
private Drawable mProgressDrawable;
- @UnsupportedAppUsage
+ /**
+ * Outside the framework, instead of accessing this directly, please use
+ * {@link #getCurrentDrawable()}, {@link #setProgressDrawable(Drawable)},
+ * {@link #setIndeterminateDrawable(Drawable)} and their tiled versions.
+ */
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private Drawable mCurrentDrawable;
private ProgressTintInfo mProgressTintInfo;
@@ -262,6 +267,8 @@ public class ProgressBar extends View {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.ProgressBar, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.ProgressBar,
+ attrs, a, defStyleAttr, defStyleRes);
mNoInvalidate = true;
@@ -1298,9 +1305,14 @@ public class ProgressBar extends View {
}
/**
- * @return The drawable currently used to draw the progress bar
+ * Returns the drawable currently used to draw the progress bar. This will be
+ * either {@link #getProgressDrawable()} or {@link #getIndeterminateDrawable()}
+ * depending on whether the progress bar is in determinate or indeterminate mode.
+ *
+ * @return the drawable currently used to draw the progress bar
*/
- Drawable getCurrentDrawable() {
+ @Nullable
+ public Drawable getCurrentDrawable() {
return mCurrentDrawable;
}
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index 757a4ca04871..f3600b0de22b 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -404,6 +404,8 @@ public class RadialTimePickerView extends View {
final Context context = getContext();
final TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.TimePicker, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.TimePicker,
+ attrs, a, defStyleAttr, defStyleRes);
final ColorStateList numbersTextColor = a.getColorStateList(
R.styleable.TimePicker_numbersTextColor);
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index ab12eaccad45..c62c16c7e719 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -98,6 +98,8 @@ public class RadioGroup extends LinearLayout {
// XML layout file
TypedArray attributes = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.RadioGroup, com.android.internal.R.attr.radioButtonStyle, 0);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.RadioGroup,
+ attrs, attributes, com.android.internal.R.attr.radioButtonStyle, 0);
int value = attributes.getResourceId(R.styleable.RadioGroup_checkedButton, View.NO_ID);
if (value != View.NO_ID) {
diff --git a/core/java/android/widget/RatingBar.java b/core/java/android/widget/RatingBar.java
index 9f9fdee46fdf..3cf3d9102d21 100644
--- a/core/java/android/widget/RatingBar.java
+++ b/core/java/android/widget/RatingBar.java
@@ -93,6 +93,8 @@ public class RatingBar extends AbsSeekBar {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.RatingBar, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.RatingBar,
+ attrs, a, defStyleAttr, defStyleRes);
final int numStars = a.getInt(R.styleable.RatingBar_numStars, mNumStars);
setIsIndicator(a.getBoolean(R.styleable.RatingBar_isIndicator, !mIsUserSeekable));
final float rating = a.getFloat(R.styleable.RatingBar_rating, -1);
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 556bfd19f942..109c0a432c1b 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -257,6 +257,8 @@ public class RelativeLayout extends ViewGroup {
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.RelativeLayout, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.RelativeLayout,
+ attrs, a, defStyleAttr, defStyleRes);
mIgnoreGravity = a.getResourceId(R.styleable.RelativeLayout_ignoreGravity, View.NO_ID);
mGravity = a.getInt(R.styleable.RelativeLayout_gravity, mGravity);
a.recycle();
diff --git a/core/java/android/widget/ScrollBarDrawable.java b/core/java/android/widget/ScrollBarDrawable.java
index e91f87e7ec3d..1bed32ecf347 100644
--- a/core/java/android/widget/ScrollBarDrawable.java
+++ b/core/java/android/widget/ScrollBarDrawable.java
@@ -17,12 +17,15 @@
package android.widget;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.view.View;
import com.android.internal.widget.ScrollBarUtils;
@@ -36,7 +39,7 @@ import com.android.internal.widget.ScrollBarUtils;
public class ScrollBarDrawable extends Drawable implements Drawable.Callback {
private Drawable mVerticalTrack;
private Drawable mHorizontalTrack;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768422)
private Drawable mVerticalThumb;
private Drawable mHorizontalThumb;
@@ -226,7 +229,10 @@ public class ScrollBarDrawable extends Drawable implements Drawable.Callback {
}
}
- @UnsupportedAppUsage
+ /**
+ * @see android.view.View#setVerticalThumbDrawable(Drawable)
+ */
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public void setVerticalThumbDrawable(Drawable thumb) {
if (mVerticalThumb != null) {
mVerticalThumb.setCallback(null);
@@ -236,6 +242,37 @@ public class ScrollBarDrawable extends Drawable implements Drawable.Callback {
mVerticalThumb = thumb;
}
+ /**
+ * @see View#getVerticalTrackDrawable()
+ */
+ public @Nullable Drawable getVerticalTrackDrawable() {
+ return mVerticalTrack;
+ }
+
+ /**
+ * @see View#getVerticalThumbDrawable()
+ */
+ public @Nullable Drawable getVerticalThumbDrawable() {
+ return mVerticalThumb;
+ }
+
+ /**
+ * @see View#getHorizontalTrackDrawable()
+ */
+ public @Nullable Drawable getHorizontalTrackDrawable() {
+ return mHorizontalTrack;
+ }
+
+ /**
+ * @see View#getHorizontalThumbDrawable()
+ */
+ public @Nullable Drawable getHorizontalThumbDrawable() {
+ return mHorizontalThumb;
+ }
+
+ /**
+ * @see android.view.View#setVerticalTrackDrawable(Drawable)
+ */
public void setVerticalTrackDrawable(Drawable track) {
if (mVerticalTrack != null) {
mVerticalTrack.setCallback(null);
@@ -245,7 +282,10 @@ public class ScrollBarDrawable extends Drawable implements Drawable.Callback {
mVerticalTrack = track;
}
- @UnsupportedAppUsage
+ /**
+ * @see android.view.View#setHorizontalThumbDrawable(Drawable)
+ */
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public void setHorizontalThumbDrawable(Drawable thumb) {
if (mHorizontalThumb != null) {
mHorizontalThumb.setCallback(null);
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 24bc9f1e4985..7e72c6a4789c 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -89,10 +90,25 @@ public class ScrollView extends FrameLayout {
private final Rect mTempRect = new Rect();
@UnsupportedAppUsage
private OverScroller mScroller;
- @UnsupportedAppUsage
- private EdgeEffect mEdgeGlowTop;
- @UnsupportedAppUsage
- private EdgeEffect mEdgeGlowBottom;
+ /**
+ * Tracks the state of the top edge glow.
+ *
+ * Even though this field is practically final, we cannot make it final because there are apps
+ * setting it via reflection and they need to keep working until they target Q.
+ */
+ @NonNull
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768600)
+ private EdgeEffect mEdgeGlowTop = new EdgeEffect(getContext());
+
+ /**
+ * Tracks the state of the bottom edge glow.
+ *
+ * Even though this field is practically final, we cannot make it final because there are apps
+ * setting it via reflection and they need to keep working until they target Q.
+ */
+ @NonNull
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769386)
+ private EdgeEffect mEdgeGlowBottom = new EdgeEffect(getContext());
/**
* Position of the last motion event.
@@ -141,13 +157,13 @@ public class ScrollView extends FrameLayout {
private boolean mSmoothScrollingEnabled = true;
private int mTouchSlop;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124051125)
private int mMinimumVelocity;
private int mMaximumVelocity;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = VERSION_CODES.P, trackingBug = 124050903)
private int mOverscrollDistance;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = VERSION_CODES.P, trackingBug = 124050903)
private int mOverflingDistance;
private float mVerticalScrollFactor;
@@ -201,6 +217,8 @@ public class ScrollView extends FrameLayout {
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.ScrollView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.ScrollView,
+ attrs, a, defStyleAttr, defStyleRes);
setFillViewport(a.getBoolean(R.styleable.ScrollView_fillViewport, false));
@@ -247,6 +265,74 @@ public class ScrollView extends FrameLayout {
}
/**
+ * Sets the edge effect color for both top and bottom edge effects.
+ *
+ * @param color The color for the edge effects.
+ * @see #setTopEdgeEffectColor(int)
+ * @see #setBottomEdgeEffectColor(int)
+ * @see #getTopEdgeEffectColor()
+ * @see #getBottomEdgeEffectColor()
+ */
+ public void setEdgeEffectColor(@ColorInt int color) {
+ setTopEdgeEffectColor(color);
+ setBottomEdgeEffectColor(color);
+ }
+
+ /**
+ * Sets the bottom edge effect color.
+ *
+ * @param color The color for the bottom edge effect.
+ * @see #setTopEdgeEffectColor(int)
+ * @see #setEdgeEffectColor(int)
+ * @see #getTopEdgeEffectColor()
+ * @see #getBottomEdgeEffectColor()
+ */
+ public void setBottomEdgeEffectColor(@ColorInt int color) {
+ mEdgeGlowBottom.setColor(color);
+ }
+
+ /**
+ * Sets the top edge effect color.
+ *
+ * @param color The color for the top edge effect.
+ * @see #setBottomEdgeEffectColor(int)
+ * @see #setEdgeEffectColor(int)
+ * @see #getTopEdgeEffectColor()
+ * @see #getBottomEdgeEffectColor()
+ */
+ public void setTopEdgeEffectColor(@ColorInt int color) {
+ mEdgeGlowTop.setColor(color);
+ }
+
+ /**
+ * Returns the top edge effect color.
+ *
+ * @return The top edge effect color.
+ * @see #setEdgeEffectColor(int)
+ * @see #setTopEdgeEffectColor(int)
+ * @see #setBottomEdgeEffectColor(int)
+ * @see #getBottomEdgeEffectColor()
+ */
+ @ColorInt
+ public int getTopEdgeEffectColor() {
+ return mEdgeGlowTop.getColor();
+ }
+
+ /**
+ * Returns the bottom edge effect color.
+ *
+ * @return The bottom edge effect color.
+ * @see #setEdgeEffectColor(int)
+ * @see #setTopEdgeEffectColor(int)
+ * @see #setBottomEdgeEffectColor(int)
+ * @see #getTopEdgeEffectColor()
+ */
+ @ColorInt
+ public int getBottomEdgeEffectColor() {
+ return mEdgeGlowBottom.getColor();
+ }
+
+ /**
* @return The maximum amount this scroll view will scroll in response to
* an arrow event.
*/
@@ -624,6 +710,10 @@ public class ScrollView extends FrameLayout {
return mIsBeingDragged;
}
+ private boolean shouldDisplayEdgeEffects() {
+ return getOverScrollMode() != OVER_SCROLL_NEVER;
+ }
+
@Override
public boolean onTouchEvent(MotionEvent ev) {
initVelocityTrackerIfNotExists();
@@ -732,7 +822,7 @@ public class ScrollView extends FrameLayout {
mEdgeGlowTop.onRelease();
}
}
- if (mEdgeGlowTop != null
+ if (shouldDisplayEdgeEffects()
&& (!mEdgeGlowTop.isFinished() || !mEdgeGlowBottom.isFinished())) {
postInvalidateOnAnimation();
}
@@ -1670,7 +1760,7 @@ public class ScrollView extends FrameLayout {
recycleVelocityTracker();
- if (mEdgeGlowTop != null) {
+ if (shouldDisplayEdgeEffects()) {
mEdgeGlowTop.onRelease();
mEdgeGlowBottom.onRelease();
}
@@ -1700,21 +1790,6 @@ public class ScrollView extends FrameLayout {
}
@Override
- public void setOverScrollMode(int mode) {
- if (mode != OVER_SCROLL_NEVER) {
- if (mEdgeGlowTop == null) {
- Context context = getContext();
- mEdgeGlowTop = new EdgeEffect(context);
- mEdgeGlowBottom = new EdgeEffect(context);
- }
- } else {
- mEdgeGlowTop = null;
- mEdgeGlowBottom = null;
- }
- super.setOverScrollMode(mode);
- }
-
- @Override
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
return (nestedScrollAxes & SCROLL_AXIS_VERTICAL) != 0;
}
@@ -1758,7 +1833,7 @@ public class ScrollView extends FrameLayout {
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
- if (mEdgeGlowTop != null) {
+ if (shouldDisplayEdgeEffects()) {
final int scrollY = mScrollY;
final boolean clipToPadding = getClipToPadding();
if (!mEdgeGlowTop.isFinished()) {
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index af3b8c0afe08..630c38a734bd 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -283,6 +283,8 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.SearchView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.SearchView,
+ attrs, a, defStyleAttr, defStyleRes);
final LayoutInflater inflater = (LayoutInflater) context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
final int layoutResId = a.getResourceId(
diff --git a/core/java/android/widget/SlidingDrawer.java b/core/java/android/widget/SlidingDrawer.java
index 8011c3aef494..2ab2b2407a50 100644
--- a/core/java/android/widget/SlidingDrawer.java
+++ b/core/java/android/widget/SlidingDrawer.java
@@ -218,6 +218,8 @@ public class SlidingDrawer extends ViewGroup {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.SlidingDrawer, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.SlidingDrawer,
+ attrs, a, defStyleAttr, defStyleRes);
int orientation = a.getInt(R.styleable.SlidingDrawer_orientation, ORIENTATION_VERTICAL);
mVertical = orientation == ORIENTATION_VERTICAL;
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index fb56d9739435..d6c657b4dc21 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -247,6 +247,8 @@ public class Spinner extends AbsSpinner implements OnClickListener {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.Spinner, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.Spinner,
+ attrs, a, defStyleAttr, defStyleRes);
if (popupTheme != null) {
mPopupContext = new ContextThemeWrapper(context, popupTheme);
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index 6cc86b9b871c..5091eea1898d 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -176,6 +176,8 @@ public class StackView extends AdapterViewAnimator {
super(context, attrs, defStyleAttr, defStyleRes);
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.StackView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.StackView,
+ attrs, a, defStyleAttr, defStyleRes);
mResOutColor = a.getColor(
com.android.internal.R.styleable.StackView_resOutColor, 0);
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index af4f0202fd6a..ea9cd421d438 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -239,6 +239,8 @@ public class Switch extends CompoundButton {
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.Switch, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.Switch,
+ attrs, a, defStyleAttr, defStyleRes);
mThumbDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_thumb);
if (mThumbDrawable != null) {
mThumbDrawable.setCallback(this);
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index b1fcbc33bbc9..481704c80287 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -93,6 +93,8 @@ public class TabHost extends FrameLayout implements ViewTreeObserver.OnTouchMode
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.TabWidget, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.TabWidget,
+ attrs, a, defStyleAttr, defStyleRes);
mTabLayoutId = a.getResourceId(R.styleable.TabWidget_tabLayout, 0);
a.recycle();
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index a90741b48684..49a0f39b3bad 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -95,6 +95,8 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.TabWidget, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.TabWidget,
+ attrs, a, defStyleAttr, defStyleRes);
mDrawBottomStrips = a.getBoolean(R.styleable.TabWidget_tabStripEnabled, mDrawBottomStrips);
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
index 7f462cb3289b..616c4b51eca0 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -242,6 +242,8 @@ public class TextClock extends TextView {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.TextClock, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.TextClock,
+ attrs, a, defStyleAttr, defStyleRes);
try {
mFormat12 = a.getText(R.styleable.TextClock_format12Hour);
mFormat24 = a.getText(R.styleable.TextClock_format24Hour);
@@ -610,8 +612,16 @@ public class TextClock extends TextView {
resolver.registerContentObserver(uri, true,
mFormatChangeObserver, UserHandle.USER_ALL);
} else {
+ // UserHandle.myUserId() is needed. This class is supported by the
+ // remote views mechanism and as a part of that the remote views
+ // can be inflated by a context for another user without the app
+ // having interact users permission - just for loading resources.
+ // For example, when adding widgets from a managed profile to the
+ // home screen. Therefore, we register the ContentObserver with the user
+ // the app is running (e.g. the launcher) and not the user of the
+ // context (e.g. the widget's profile).
resolver.registerContentObserver(uri, true,
- mFormatChangeObserver);
+ mFormatChangeObserver, UserHandle.myUserId());
}
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d87600125a54..51eaa12aa314 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -664,7 +664,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@UnsupportedAppUsage
private CharWrapper mCharWrapper;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(trackingBug = 124050217)
private Marquee mMarquee;
@UnsupportedAppUsage
private boolean mRestartMarquee;
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index b239ce638e68..97a8ade589d1 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -127,6 +127,8 @@ public class TimePicker extends FrameLayout {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.TimePicker, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.TimePicker,
+ attrs, a, defStyleAttr, defStyleRes);
final boolean isDialogMode = a.getBoolean(R.styleable.TimePicker_dialogMode, false);
final int requestedMode = a.getInt(R.styleable.TimePicker_timePickerMode, MODE_SPINNER);
a.recycle();
diff --git a/core/java/android/widget/ToggleButton.java b/core/java/android/widget/ToggleButton.java
index bba6da6b7b4c..b76c2cafd912 100644
--- a/core/java/android/widget/ToggleButton.java
+++ b/core/java/android/widget/ToggleButton.java
@@ -48,6 +48,8 @@ public class ToggleButton extends CompoundButton {
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.ToggleButton, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.ToggleButton,
+ attrs, a, defStyleAttr, defStyleRes);
mTextOn = a.getText(com.android.internal.R.styleable.ToggleButton_textOn);
mTextOff = a.getText(com.android.internal.R.styleable.ToggleButton_textOff);
mDisabledAlpha = a.getFloat(com.android.internal.R.styleable.ToggleButton_disabledAlpha, 0.5f);
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index a33c47d86673..f25109ee82df 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -237,6 +237,8 @@ public class Toolbar extends ViewGroup {
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Toolbar,
defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.Toolbar,
+ attrs, a, defStyleAttr, defStyleRes);
mTitleTextAppearance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0);
mSubtitleTextAppearance = a.getResourceId(R.styleable.Toolbar_subtitleTextAppearance, 0);
diff --git a/core/java/android/widget/TwoLineListItem.java b/core/java/android/widget/TwoLineListItem.java
index 553b86e1f0c2..4c613a71a3ac 100644
--- a/core/java/android/widget/TwoLineListItem.java
+++ b/core/java/android/widget/TwoLineListItem.java
@@ -62,6 +62,8 @@ public class TwoLineListItem extends RelativeLayout {
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.TwoLineListItem, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.TwoLineListItem,
+ attrs, a, defStyleAttr, defStyleRes);
a.recycle();
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 119a015cd5ea..585a1f1da417 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -46,6 +46,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
+import android.database.Cursor;
import android.database.DataSetObserver;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -69,6 +70,8 @@ import android.os.ResultReceiver;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
+import android.provider.DocumentsContract;
+import android.provider.OpenableColumns;
import android.service.chooser.ChooserTarget;
import android.service.chooser.ChooserTargetService;
import android.service.chooser.IChooserTargetResult;
@@ -87,7 +90,6 @@ import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
-import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
@@ -373,50 +375,6 @@ public class ChooserActivity extends ResolverActivity {
super.onCreate(savedInstanceState, target, title, defaultTitleRes, initialIntents,
null, false);
- Button copyButton = findViewById(R.id.copy_button);
- copyButton.setOnClickListener(view -> {
- Intent targetIntent = getTargetIntent();
- if (targetIntent == null) {
- finish();
- } else {
- final String action = targetIntent.getAction();
-
- ClipData clipData = null;
- if (Intent.ACTION_SEND.equals(action)) {
- String extraText = targetIntent.getStringExtra(Intent.EXTRA_TEXT);
- Uri extraStream = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM);
-
- if (extraText != null) {
- clipData = ClipData.newPlainText(null, extraText);
- } else if (extraStream != null) {
- clipData = ClipData.newUri(getContentResolver(), null, extraStream);
- } else {
- Log.w(TAG, "No data available to copy to clipboard");
- return;
- }
- } else if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
- final ArrayList<Uri> streams = targetIntent.getParcelableArrayListExtra(
- Intent.EXTRA_STREAM);
- clipData = ClipData.newUri(getContentResolver(), null, streams.get(0));
- for (int i = 1; i < streams.size(); i++) {
- clipData.addItem(getContentResolver(), new ClipData.Item(streams.get(i)));
- }
- } else {
- // expected to only be visible with ACTION_SEND or ACTION_SEND_MULTIPLE
- // so warn about unexpected action
- Log.w(TAG, "Action (" + action + ") not supported for copying to clipboard");
- return;
- }
-
- ClipboardManager clipboardManager = (ClipboardManager) getSystemService(
- Context.CLIPBOARD_SERVICE);
- clipboardManager.setPrimaryClip(clipData);
- Toast.makeText(getApplicationContext(), R.string.copied, Toast.LENGTH_SHORT).show();
-
- finish();
- }
- });
-
mChooserShownTime = System.currentTimeMillis();
final long systemCost = mChooserShownTime - intentReceivedTime;
@@ -474,6 +432,10 @@ public class ChooserActivity extends ResolverActivity {
return;
}
+ if (mChooserListAdapter == null || mChooserListAdapter.getCount() == 0) {
+ return;
+ }
+
int previewType = findPreferredContentPreview(targetIntent, getContentResolver());
getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_SHARE_WITH_PREVIEW)
@@ -481,6 +443,49 @@ public class ChooserActivity extends ResolverActivity {
displayContentPreview(previewType, targetIntent);
}
+ private void onCopyButtonClicked(View v) {
+ Intent targetIntent = getTargetIntent();
+ if (targetIntent == null) {
+ finish();
+ } else {
+ final String action = targetIntent.getAction();
+
+ ClipData clipData = null;
+ if (Intent.ACTION_SEND.equals(action)) {
+ String extraText = targetIntent.getStringExtra(Intent.EXTRA_TEXT);
+ Uri extraStream = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM);
+
+ if (extraText != null) {
+ clipData = ClipData.newPlainText(null, extraText);
+ } else if (extraStream != null) {
+ clipData = ClipData.newUri(getContentResolver(), null, extraStream);
+ } else {
+ Log.w(TAG, "No data available to copy to clipboard");
+ return;
+ }
+ } else if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
+ final ArrayList<Uri> streams = targetIntent.getParcelableArrayListExtra(
+ Intent.EXTRA_STREAM);
+ clipData = ClipData.newUri(getContentResolver(), null, streams.get(0));
+ for (int i = 1; i < streams.size(); i++) {
+ clipData.addItem(getContentResolver(), new ClipData.Item(streams.get(i)));
+ }
+ } else {
+ // expected to only be visible with ACTION_SEND or ACTION_SEND_MULTIPLE
+ // so warn about unexpected action
+ Log.w(TAG, "Action (" + action + ") not supported for copying to clipboard");
+ return;
+ }
+
+ ClipboardManager clipboardManager = (ClipboardManager) getSystemService(
+ Context.CLIPBOARD_SERVICE);
+ clipboardManager.setPrimaryClip(clipData);
+ Toast.makeText(getApplicationContext(), R.string.copied, Toast.LENGTH_SHORT).show();
+
+ finish();
+ }
+ }
+
private void displayContentPreview(@ContentPreviewType int previewType, Intent targetIntent) {
switch (previewType) {
case CONTENT_PREVIEW_TEXT:
@@ -501,6 +506,8 @@ public class ChooserActivity extends ResolverActivity {
ViewGroup contentPreviewLayout = findViewById(R.id.content_preview_text_area);
contentPreviewLayout.setVisibility(View.VISIBLE);
+ findViewById(R.id.copy_button).setOnClickListener(this::onCopyButtonClicked);
+
CharSequence sharingText = targetIntent.getCharSequenceExtra(Intent.EXTRA_TEXT);
if (sharingText == null) {
findViewById(R.id.content_preview_text_layout).setVisibility(View.GONE);
@@ -510,7 +517,7 @@ public class ChooserActivity extends ResolverActivity {
}
String previewTitle = targetIntent.getStringExtra(Intent.EXTRA_TITLE);
- if (previewTitle == null || previewTitle.trim().isEmpty()) {
+ if (TextUtils.isEmpty(previewTitle)) {
findViewById(R.id.content_preview_title_layout).setVisibility(View.GONE);
} else {
TextView previewTitleView = findViewById(R.id.content_preview_title);
@@ -561,6 +568,7 @@ public class ChooserActivity extends ResolverActivity {
if (imageUris.size() == 0) {
Log.i(TAG, "Attempted to display image preview area with zero"
+ " available images detected in EXTRA_STREAM list");
+ contentPreviewLayout.setVisibility(View.GONE);
return;
}
@@ -580,15 +588,101 @@ public class ChooserActivity extends ResolverActivity {
}
}
+ private static class FileInfo {
+ public final String name;
+ public final boolean hasThumbnail;
+
+ FileInfo(String name, boolean hasThumbnail) {
+ this.name = name;
+ this.hasThumbnail = hasThumbnail;
+ }
+ }
+
+ private FileInfo extractFileInfo(Uri uri, ContentResolver resolver) {
+ String fileName = null;
+ boolean hasThumbnail = false;
+ Cursor cursor = resolver.query(uri, null, null, null, null);
+ if (cursor != null && cursor.getCount() > 0) {
+ int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
+ int flagsIndex = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_FLAGS);
+
+ cursor.moveToFirst();
+ fileName = cursor.getString(nameIndex);
+ if (flagsIndex != -1) {
+ hasThumbnail = (cursor.getInt(flagsIndex)
+ & DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
+ }
+ }
+
+ if (TextUtils.isEmpty(fileName)) {
+ fileName = uri.getPath();
+ int index = fileName.lastIndexOf('/');
+ if (index != -1) {
+ fileName = fileName.substring(index + 1);
+ }
+ }
+
+ return new FileInfo(fileName, hasThumbnail);
+ }
+
private void displayFileContentPreview(Intent targetIntent) {
- // support coming
+ ViewGroup contentPreviewLayout = findViewById(R.id.content_preview_file_area);
+ contentPreviewLayout.setVisibility(View.VISIBLE);
+
+ // TODO(b/120417119): Disable file copy until after moving to sysui,
+ // due to permissions issues
+ findViewById(R.id.file_copy_button).setVisibility(View.GONE);
+
+ try {
+ ContentResolver resolver = getContentResolver();
+ TextView fileNameView = findViewById(R.id.content_preview_filename);
+ String action = targetIntent.getAction();
+ if (Intent.ACTION_SEND.equals(action)) {
+ Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM);
+
+ FileInfo fileInfo = extractFileInfo(uri, resolver);
+ fileNameView.setText(fileInfo.name);
+
+ if (fileInfo.hasThumbnail) {
+ loadUriIntoView(R.id.content_preview_file_thumbnail, uri);
+ } else {
+ ImageView fileIconView = findViewById(R.id.content_preview_file_icon);
+ fileIconView.setVisibility(View.VISIBLE);
+ fileIconView.setImageResource(R.drawable.ic_doc_generic);
+ }
+ } else {
+ List<Uri> uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
+ if (uris.size() == 0) {
+ contentPreviewLayout.setVisibility(View.GONE);
+ Log.i(TAG,
+ "Appears to be no uris available in EXTRA_STREAM, removing preview "
+ + "area");
+ return;
+ }
+
+ FileInfo fileInfo = extractFileInfo(uris.get(0), resolver);
+ int remFileCount = uris.size() - 1;
+ String fileName = getResources().getQuantityString(R.plurals.file_count,
+ remFileCount, fileInfo.name, remFileCount);
+
+ fileNameView.setText(fileName);
+ ImageView fileIconView = findViewById(R.id.content_preview_file_icon);
+ fileIconView.setVisibility(View.VISIBLE);
+ fileIconView.setImageResource(R.drawable.ic_file_copy);
+ }
+ } catch (SecurityException e) {
+ Log.w(TAG, "Error loading file preview", e);
+ contentPreviewLayout.setVisibility(View.GONE);
+ }
}
private RoundedRectImageView loadUriIntoView(int imageResourceId, Uri uri) {
RoundedRectImageView imageView = findViewById(imageResourceId);
- imageView.setVisibility(View.VISIBLE);
Bitmap bmp = loadThumbnail(uri, new Size(200, 200));
- imageView.setImageBitmap(bmp);
+ if (bmp != null) {
+ imageView.setVisibility(View.VISIBLE);
+ imageView.setImageBitmap(bmp);
+ }
return imageView;
}
@@ -1261,9 +1355,8 @@ public class ChooserActivity extends ResolverActivity {
}
try {
- return ImageUtils.decodeSampledBitmapFromStream(getContentResolver(),
- uri, size.getWidth(), size.getHeight());
- } catch (IOException | NullPointerException ex) {
+ return ImageUtils.loadThumbnail(getContentResolver(), uri, size);
+ } catch (IOException | NullPointerException | SecurityException ex) {
Log.w(TAG, "Error loading preview thumbnail for uri: " + uri.toString(), ex);
}
return null;
diff --git a/core/java/com/android/internal/colorextraction/ColorExtractor.java b/core/java/com/android/internal/colorextraction/ColorExtractor.java
index c171fa6b25fd..258d081c6ad8 100644
--- a/core/java/com/android/internal/colorextraction/ColorExtractor.java
+++ b/core/java/com/android/internal/colorextraction/ColorExtractor.java
@@ -22,7 +22,6 @@ import android.app.WallpaperColors;
import android.app.WallpaperManager;
import android.content.Context;
import android.os.Trace;
-import android.os.UserHandle;
import android.util.Log;
import android.util.SparseArray;
@@ -32,7 +31,6 @@ import com.android.internal.colorextraction.types.Tonal;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.Iterator;
/**
* Class to process wallpaper colors and generate a tonal palette based on them.
@@ -222,6 +220,7 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener
public static class GradientColors {
private int mMainColor;
private int mSecondaryColor;
+ private int[] mColorPalette;
private boolean mSupportsDarkText;
public void setMainColor(int mainColor) {
@@ -232,6 +231,10 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener
mSecondaryColor = secondaryColor;
}
+ public void setColorPalette(int[] colorPalette) {
+ mColorPalette = colorPalette;
+ }
+
public void setSupportsDarkText(boolean supportsDarkText) {
mSupportsDarkText = supportsDarkText;
}
@@ -239,6 +242,7 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener
public void set(GradientColors other) {
mMainColor = other.mMainColor;
mSecondaryColor = other.mSecondaryColor;
+ mColorPalette = other.mColorPalette;
mSupportsDarkText = other.mSupportsDarkText;
}
@@ -250,6 +254,10 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener
return mSecondaryColor;
}
+ public int[] getColorPalette() {
+ return mColorPalette;
+ }
+
public boolean supportsDarkText() {
return mSupportsDarkText;
}
@@ -283,4 +291,4 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener
public interface OnColorsChangedListener {
void onColorsChanged(ColorExtractor colorExtractor, int which);
}
-} \ No newline at end of file
+}
diff --git a/core/java/com/android/internal/colorextraction/types/Tonal.java b/core/java/com/android/internal/colorextraction/types/Tonal.java
index 3fd88dbb8704..d6a8934566b2 100644
--- a/core/java/com/android/internal/colorextraction/types/Tonal.java
+++ b/core/java/com/android/internal/colorextraction/types/Tonal.java
@@ -173,6 +173,7 @@ public class Tonal implements ExtractionType {
Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY);
float[] s = fit(palette.s, hsl[1], fitIndex, 0.0f, 1.0f);
float[] l = fit(palette.l, hsl[2], fitIndex, 0.0f, 1.0f);
+ int[] colorPalette = getColorPalette(h, s, l);
if (DEBUG) {
StringBuilder builder = new StringBuilder("Tonal Palette - index: " + fitIndex +
@@ -209,6 +210,7 @@ public class Tonal implements ExtractionType {
// Normal colors:
outColorsNormal.setMainColor(mainColor);
outColorsNormal.setSecondaryColor(mainColor);
+ outColorsNormal.setColorPalette(colorPalette);
// Dark colors:
// Stops at 4th color, only lighter if dark text is supported
@@ -222,6 +224,7 @@ public class Tonal implements ExtractionType {
mainColor = getColorInt(primaryIndex, h, s, l);
outColorsDark.setMainColor(mainColor);
outColorsDark.setSecondaryColor(mainColor);
+ outColorsDark.setColorPalette(colorPalette);
// Extra Dark:
// Stay close to dark colors until dark text is supported
@@ -235,6 +238,7 @@ public class Tonal implements ExtractionType {
mainColor = getColorInt(primaryIndex, h, s, l);
outColorsExtraDark.setMainColor(mainColor);
outColorsExtraDark.setSecondaryColor(mainColor);
+ outColorsExtraDark.setColorPalette(colorPalette);
outColorsNormal.setSupportsDarkText(supportsDarkText);
outColorsDark.setSupportsDarkText(supportsDarkText);
@@ -262,16 +266,19 @@ public class Tonal implements ExtractionType {
* @param inWallpaperColors Colors to read.
* @param outGradientColors Destination.
*/
- public static void applyFallback(@Nullable WallpaperColors inWallpaperColors,
+ public void applyFallback(@Nullable WallpaperColors inWallpaperColors,
@NonNull GradientColors outGradientColors) {
boolean light = inWallpaperColors != null
&& (inWallpaperColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT)
!= 0;
final int color = light ? MAIN_COLOR_LIGHT : MAIN_COLOR_DARK;
+ final float[] hsl = new float[3];
+ ColorUtils.colorToHSL(color, hsl);
outGradientColors.setMainColor(color);
outGradientColors.setSecondaryColor(color);
outGradientColors.setSupportsDarkText(light);
+ outGradientColors.setColorPalette(getColorPalette(findTonalPalette(hsl[0], hsl[1])));
}
private int getColorInt(int fitIndex, float[] h, float[] s, float[] l) {
@@ -281,6 +288,19 @@ public class Tonal implements ExtractionType {
return ColorUtils.HSLToColor(mTmpHSL);
}
+ private int[] getColorPalette(float[] h, float[] s, float[] l) {
+ int[] colorPalette = new int[h.length];
+ for (int i = 0; i < colorPalette.length; i++) {
+ colorPalette[i] = getColorInt(i, h, s, l);
+ }
+ return colorPalette;
+ }
+
+ private int[] getColorPalette(TonalPalette palette) {
+ return getColorPalette(palette.h, palette.s, palette.l);
+ }
+
+
/**
* Checks if a given color exists in the blacklist
* @param hsl float array with 3 components (H 0..360, S 0..1 and L 0..1)
@@ -598,4 +618,4 @@ public class Tonal implements ExtractionType {
return numbers;
}
}
-} \ No newline at end of file
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 52e1748c621c..4ff99482feff 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -187,6 +187,8 @@ public class BatteryStatsImpl extends BatteryStats {
static final int MSG_REPORT_RESET_STATS = 4;
static final long DELAY_UPDATE_WAKELOCKS = 5*1000;
+ private static final double MILLISECONDS_IN_HOUR = 3600 * 1000;
+
private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
@@ -252,6 +254,9 @@ public class BatteryStatsImpl extends BatteryStats {
private static final long RPM_STATS_UPDATE_FREQ_MS = 1000;
/** Last time that RPM stats were updated by updateRpmStatsLocked. */
private long mLastRpmStatsUpdateTimeMs = -RPM_STATS_UPDATE_FREQ_MS;
+
+ /** Container for Rail Energy Data stats. */
+ private final RailStats mTmpRailStats = new RailStats();
/**
* Use a queue to delay removing UIDs from {@link KernelCpuUidUserSysTimeReader},
* {@link KernelCpuUidActiveTimeReader}, {@link KernelCpuUidClusterTimeReader},
@@ -327,6 +332,15 @@ public class BatteryStatsImpl extends BatteryStats {
public String getSubsystemLowPowerStats();
}
+ /** interface to update rail information for power monitor */
+ public interface RailEnergyDataCallback {
+ /** Function to fill the map for the rail data stats
+ * Used for power monitoring feature
+ * @param railStats
+ */
+ void fillRailDataStats(RailStats railStats);
+ }
+
public static abstract class UserInfoProvider {
private int[] userIds;
protected abstract @Nullable int[] getUserIds();
@@ -361,6 +375,8 @@ public class BatteryStatsImpl extends BatteryStats {
}
};
+ public final RailEnergyDataCallback mRailEnergyDataCallback;
+
/**
* This handler is running on {@link BackgroundThread}.
*/
@@ -593,7 +609,9 @@ public class BatteryStatsImpl extends BatteryStats {
int UPDATE_RADIO = 0x04;
int UPDATE_BT = 0x08;
int UPDATE_RPM = 0x10; // 16
- int UPDATE_ALL = UPDATE_CPU | UPDATE_WIFI | UPDATE_RADIO | UPDATE_BT | UPDATE_RPM;
+ int UPDATE_RAIL = 0x20; // 32
+ int UPDATE_ALL = UPDATE_CPU | UPDATE_WIFI | UPDATE_RADIO | UPDATE_BT | UPDATE_RPM
+ | UPDATE_RAIL;
Future<?> scheduleSync(String reason, int flags);
Future<?> scheduleCpuSyncDueToRemovedUid(int uid);
@@ -1078,6 +1096,7 @@ public class BatteryStatsImpl extends BatteryStats {
mBatteryStatsHistory = null;
mHandler = null;
mPlatformIdleStateCallback = null;
+ mRailEnergyDataCallback = null;
mUserInfoProvider = null;
mConstants = new Constants(mHandler);
clearHistoryLocked();
@@ -3005,6 +3024,7 @@ public class BatteryStatsImpl extends BatteryStats {
private final LongSamplingCounter mRxTimeMillis;
private final LongSamplingCounter[] mTxTimeMillis;
private final LongSamplingCounter mPowerDrainMaMs;
+ private final LongSamplingCounter mMonitoredRailChargeConsumedMaMs;
public ControllerActivityCounterImpl(TimeBase timeBase, int numTxStates) {
mIdleTimeMillis = new LongSamplingCounter(timeBase);
@@ -3016,6 +3036,7 @@ public class BatteryStatsImpl extends BatteryStats {
mTxTimeMillis[i] = new LongSamplingCounter(timeBase);
}
mPowerDrainMaMs = new LongSamplingCounter(timeBase);
+ mMonitoredRailChargeConsumedMaMs = new LongSamplingCounter(timeBase);
}
public ControllerActivityCounterImpl(TimeBase timeBase, int numTxStates, Parcel in) {
@@ -3033,6 +3054,7 @@ public class BatteryStatsImpl extends BatteryStats {
mTxTimeMillis[i] = new LongSamplingCounter(timeBase, in);
}
mPowerDrainMaMs = new LongSamplingCounter(timeBase, in);
+ mMonitoredRailChargeConsumedMaMs = new LongSamplingCounter(timeBase, in);
}
public void readSummaryFromParcel(Parcel in) {
@@ -3048,6 +3070,7 @@ public class BatteryStatsImpl extends BatteryStats {
counter.readSummaryFromParcelLocked(in);
}
mPowerDrainMaMs.readSummaryFromParcelLocked(in);
+ mMonitoredRailChargeConsumedMaMs.readSummaryFromParcelLocked(in);
}
@Override
@@ -3065,6 +3088,7 @@ public class BatteryStatsImpl extends BatteryStats {
counter.writeSummaryFromParcelLocked(dest);
}
mPowerDrainMaMs.writeSummaryFromParcelLocked(dest);
+ mMonitoredRailChargeConsumedMaMs.writeSummaryFromParcelLocked(dest);
}
@Override
@@ -3078,6 +3102,7 @@ public class BatteryStatsImpl extends BatteryStats {
counter.writeToParcel(dest);
}
mPowerDrainMaMs.writeToParcel(dest);
+ mMonitoredRailChargeConsumedMaMs.writeToParcel(dest);
}
public void reset(boolean detachIfReset) {
@@ -3089,6 +3114,7 @@ public class BatteryStatsImpl extends BatteryStats {
counter.reset(detachIfReset);
}
mPowerDrainMaMs.reset(detachIfReset);
+ mMonitoredRailChargeConsumedMaMs.reset(detachIfReset);
}
public void detach() {
@@ -3100,6 +3126,7 @@ public class BatteryStatsImpl extends BatteryStats {
counter.detach();
}
mPowerDrainMaMs.detach();
+ mMonitoredRailChargeConsumedMaMs.detach();
}
/**
@@ -3154,6 +3181,15 @@ public class BatteryStatsImpl extends BatteryStats {
public LongSamplingCounter getPowerCounter() {
return mPowerDrainMaMs;
}
+
+ /**
+ * @return a LongSamplingCounter, measuring actual monitored rail energy consumed
+ * milli-ampere milli-seconds (mAmS).
+ */
+ @Override
+ public LongSamplingCounter getMonitoredRailChargeConsumedMaMs() {
+ return mMonitoredRailChargeConsumedMaMs;
+ }
}
/** Get Resource Power Manager stats. Create a new one if it doesn't already exist. */
@@ -3497,6 +3533,8 @@ public class BatteryStatsImpl extends BatteryStats {
if (DEBUG) Slog.i(TAG, "WRITE DELTA: batteryChargeUAh=" + cur.batteryChargeUAh);
dest.writeInt(cur.batteryChargeUAh);
}
+ dest.writeDouble(cur.modemRailChargeMah);
+ dest.writeDouble(cur.wifiRailChargeMah);
}
private int buildBatteryLevelInt(HistoryItem h) {
@@ -3747,6 +3785,8 @@ public class BatteryStatsImpl extends BatteryStats {
if ((firstToken&DELTA_BATTERY_CHARGE_FLAG) != 0) {
cur.batteryChargeUAh = src.readInt();
}
+ cur.modemRailChargeMah = src.readDouble();
+ cur.wifiRailChargeMah = src.readDouble();
}
@Override
@@ -10111,12 +10151,12 @@ public class BatteryStatsImpl extends BatteryStats {
}
public BatteryStatsImpl(File systemDir, Handler handler, PlatformIdleStateCallback cb,
- UserInfoProvider userInfoProvider) {
- this(new SystemClocks(), systemDir, handler, cb, userInfoProvider);
+ RailEnergyDataCallback railStatsCb, UserInfoProvider userInfoProvider) {
+ this(new SystemClocks(), systemDir, handler, cb, railStatsCb, userInfoProvider);
}
private BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler,
- PlatformIdleStateCallback cb,
+ PlatformIdleStateCallback cb, RailEnergyDataCallback railStatsCb,
UserInfoProvider userInfoProvider) {
init(clocks);
@@ -10218,6 +10258,7 @@ public class BatteryStatsImpl extends BatteryStats {
clearHistoryLocked();
updateDailyDeadlineLocked();
mPlatformIdleStateCallback = cb;
+ mRailEnergyDataCallback = railStatsCb;
mUserInfoProvider = userInfoProvider;
}
@@ -10238,6 +10279,7 @@ public class BatteryStatsImpl extends BatteryStats {
mBatteryStatsHistory = new BatteryStatsHistory(this, mHistoryBuffer);
readFromParcel(p);
mPlatformIdleStateCallback = null;
+ mRailEnergyDataCallback = null;
}
public void setPowerProfileLocked(PowerProfile profile) {
@@ -10934,6 +10976,8 @@ public class BatteryStatsImpl extends BatteryStats {
mWakeupReasonStats.clear();
}
+ mTmpRailStats.reset();
+
mLastHistoryStepDetails = null;
mLastStepCpuUserTime = mLastStepCpuSystemTime = 0;
mCurStepCpuUserTime = mCurStepCpuSystemTime = 0;
@@ -11321,6 +11365,16 @@ public class BatteryStatsImpl extends BatteryStats {
mWifiActivity.getPowerCounter().addCountLocked(
(long) (info.getControllerEnergyUsed() / opVolt));
}
+ // Converting uWs to mAms.
+ // Conversion: (uWs * (1000ms / 1s) * (1mW / 1000uW)) / mV = mAms
+ long monitoredRailChargeConsumedMaMs =
+ (long) (mTmpRailStats.getWifiTotalEnergyUseduWs() / opVolt);
+ mWifiActivity.getMonitoredRailChargeConsumedMaMs().addCountLocked(
+ monitoredRailChargeConsumedMaMs);
+ mHistoryCur.wifiRailChargeMah +=
+ (monitoredRailChargeConsumedMaMs / MILLISECONDS_IN_HOUR);
+ addHistoryRecordLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mTmpRailStats.resetWifiTotalEnergyUsed();
}
}
}
@@ -11411,9 +11465,18 @@ public class BatteryStatsImpl extends BatteryStats {
// We store the power drain as mAms.
mModemActivity.getPowerCounter().addCountLocked((long) energyUsed);
+ // Converting uWs to mAms.
+ // Conversion: (uWs * (1000ms / 1s) * (1mW / 1000uW)) / mV = mAms
+ long monitoredRailChargeConsumedMaMs =
+ (long) (mTmpRailStats.getCellularTotalEnergyUseduWs() / opVolt);
+ mModemActivity.getMonitoredRailChargeConsumedMaMs().addCountLocked(
+ monitoredRailChargeConsumedMaMs);
+ mHistoryCur.modemRailChargeMah +=
+ (monitoredRailChargeConsumedMaMs / MILLISECONDS_IN_HOUR);
+ addHistoryRecordLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+ mTmpRailStats.resetCellularTotalEnergyUsed();
}
}
-
final long elapsedRealtimeMs = mClocks.elapsedRealtime();
long radioTime = mMobileRadioActivePerAppTimer.getTimeSinceMarkLocked(
elapsedRealtimeMs * 1000);
@@ -11812,6 +11875,16 @@ public class BatteryStatsImpl extends BatteryStats {
}
/**
+ * Read and record Rail Energy data.
+ */
+ public void updateRailStatsLocked() {
+ if (mRailEnergyDataCallback == null || !mTmpRailStats.isRailStatsAvailable()) {
+ return;
+ }
+ mRailEnergyDataCallback.fillRailDataStats(mTmpRailStats);
+ }
+
+ /**
* Read and distribute kernel wake lock use across apps.
*/
public void updateKernelWakelocksLocked() {
@@ -12950,6 +13023,8 @@ public class BatteryStatsImpl extends BatteryStats {
final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(which);
final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(which);
final long energyConsumedMaMs = counter.getPowerCounter().getCountLocked(which);
+ final long monitoredRailChargeConsumedMaMs =
+ counter.getMonitoredRailChargeConsumedMaMs().getCountLocked(which);
long[] timeInRatMs = new long[BatteryStats.NUM_DATA_CONNECTION_TYPES];
for (int i = 0; i < timeInRatMs.length; i++) {
timeInRatMs[i] = getPhoneDataConnectionTime(i, rawRealTime, which) / 1000;
@@ -12979,58 +13054,62 @@ public class BatteryStatsImpl extends BatteryStats {
s.setTimeInRatMs(timeInRatMs);
s.setTimeInRxSignalStrengthLevelMs(timeInRxSignalStrengthLevelMs);
s.setTxTimeMs(txTimeMs);
+ s.setMonitoredRailChargeConsumedMaMs(monitoredRailChargeConsumedMaMs);
return s;
}
- /*@hide */
- public WifiBatteryStats getWifiBatteryStats() {
- WifiBatteryStats s = new WifiBatteryStats();
- final int which = STATS_SINCE_CHARGED;
- final long rawRealTime = SystemClock.elapsedRealtime() * 1000;
- final ControllerActivityCounter counter = getWifiControllerActivity();
- final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(which);
- final long scanTimeMs = counter.getScanTimeCounter().getCountLocked(which);
- final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(which);
- final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(which);
- final long totalControllerActivityTimeMs
- = computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which) / 1000;
- final long sleepTimeMs
- = totalControllerActivityTimeMs - (idleTimeMs + rxTimeMs + txTimeMs);
- final long energyConsumedMaMs = counter.getPowerCounter().getCountLocked(which);
- long numAppScanRequest = 0;
- for (int i = 0; i < mUidStats.size(); i++) {
- numAppScanRequest += mUidStats.valueAt(i).mWifiScanTimer.getCountLocked(which);
- }
- long[] timeInStateMs = new long[NUM_WIFI_STATES];
- for (int i=0; i<NUM_WIFI_STATES; i++) {
+ /*@hide */
+ public WifiBatteryStats getWifiBatteryStats() {
+ WifiBatteryStats s = new WifiBatteryStats();
+ final int which = STATS_SINCE_CHARGED;
+ final long rawRealTime = SystemClock.elapsedRealtime() * 1000;
+ final ControllerActivityCounter counter = getWifiControllerActivity();
+ final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(which);
+ final long scanTimeMs = counter.getScanTimeCounter().getCountLocked(which);
+ final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(which);
+ final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(which);
+ final long totalControllerActivityTimeMs
+ = computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which) / 1000;
+ final long sleepTimeMs
+ = totalControllerActivityTimeMs - (idleTimeMs + rxTimeMs + txTimeMs);
+ final long energyConsumedMaMs = counter.getPowerCounter().getCountLocked(which);
+ final long monitoredRailChargeConsumedMaMs =
+ counter.getMonitoredRailChargeConsumedMaMs().getCountLocked(which);
+ long numAppScanRequest = 0;
+ for (int i = 0; i < mUidStats.size(); i++) {
+ numAppScanRequest += mUidStats.valueAt(i).mWifiScanTimer.getCountLocked(which);
+ }
+ long[] timeInStateMs = new long[NUM_WIFI_STATES];
+ for (int i=0; i<NUM_WIFI_STATES; i++) {
timeInStateMs[i] = getWifiStateTime(i, rawRealTime, which) / 1000;
- }
- long[] timeInSupplStateMs = new long[NUM_WIFI_SUPPL_STATES];
- for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
- timeInSupplStateMs[i] = getWifiSupplStateTime(i, rawRealTime, which) / 1000;
- }
- long[] timeSignalStrengthTimeMs = new long[NUM_WIFI_SIGNAL_STRENGTH_BINS];
- for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
- timeSignalStrengthTimeMs[i] = getWifiSignalStrengthTime(i, rawRealTime, which) / 1000;
- }
- s.setLoggingDurationMs(computeBatteryRealtime(rawRealTime, which) / 1000);
- s.setKernelActiveTimeMs(getWifiActiveTime(rawRealTime, which) / 1000);
- s.setNumPacketsTx(getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which));
- s.setNumBytesTx(getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which));
- s.setNumPacketsRx(getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which));
- s.setNumBytesRx(getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which));
- s.setSleepTimeMs(sleepTimeMs);
- s.setIdleTimeMs(idleTimeMs);
- s.setRxTimeMs(rxTimeMs);
- s.setTxTimeMs(txTimeMs);
- s.setScanTimeMs(scanTimeMs);
- s.setEnergyConsumedMaMs(energyConsumedMaMs);
- s.setNumAppScanRequest(numAppScanRequest);
- s.setTimeInStateMs(timeInStateMs);
- s.setTimeInSupplicantStateMs(timeInSupplStateMs);
- s.setTimeInRxSignalStrengthLevelMs(timeSignalStrengthTimeMs);
- return s;
- }
+ }
+ long[] timeInSupplStateMs = new long[NUM_WIFI_SUPPL_STATES];
+ for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
+ timeInSupplStateMs[i] = getWifiSupplStateTime(i, rawRealTime, which) / 1000;
+ }
+ long[] timeSignalStrengthTimeMs = new long[NUM_WIFI_SIGNAL_STRENGTH_BINS];
+ for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
+ timeSignalStrengthTimeMs[i] = getWifiSignalStrengthTime(i, rawRealTime, which) / 1000;
+ }
+ s.setLoggingDurationMs(computeBatteryRealtime(rawRealTime, which) / 1000);
+ s.setKernelActiveTimeMs(getWifiActiveTime(rawRealTime, which) / 1000);
+ s.setNumPacketsTx(getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which));
+ s.setNumBytesTx(getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which));
+ s.setNumPacketsRx(getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which));
+ s.setNumBytesRx(getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which));
+ s.setSleepTimeMs(sleepTimeMs);
+ s.setIdleTimeMs(idleTimeMs);
+ s.setRxTimeMs(rxTimeMs);
+ s.setTxTimeMs(txTimeMs);
+ s.setScanTimeMs(scanTimeMs);
+ s.setEnergyConsumedMaMs(energyConsumedMaMs);
+ s.setNumAppScanRequest(numAppScanRequest);
+ s.setTimeInStateMs(timeInStateMs);
+ s.setTimeInSupplicantStateMs(timeInSupplStateMs);
+ s.setTimeInRxSignalStrengthLevelMs(timeSignalStrengthTimeMs);
+ s.setMonitoredRailChargeConsumedMaMs(monitoredRailChargeConsumedMaMs);
+ return s;
+ }
/*@hide */
public GpsBatteryStats getGpsBatteryStats() {
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index 2c272dea073b..7f4d8a2d0587 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -52,6 +52,8 @@ public class BinderCallsStats implements BinderInternal.Observer {
public static final boolean ENABLED_DEFAULT = true;
public static final boolean DETAILED_TRACKING_DEFAULT = true;
public static final int PERIODIC_SAMPLING_INTERVAL_DEFAULT = 100;
+ public static final boolean DEFAULT_TRACK_SCREEN_INTERACTIVE = false;
+ public static final boolean DEFAULT_TRACK_DIRECT_CALLING_UID = true;
public static final int MAX_BINDER_CALL_STATS_COUNT_DEFAULT = 5000;
private static final String DEBUG_ENTRY_PREFIX = "__DEBUG_";
@@ -85,6 +87,8 @@ public class BinderCallsStats implements BinderInternal.Observer {
private long mStartElapsedTime = SystemClock.elapsedRealtime();
private long mCallStatsCount = 0;
private boolean mAddDebugEntries = false;
+ private boolean mTrackDirectCallingUid = DEFAULT_TRACK_DIRECT_CALLING_UID;
+ private boolean mTrackScreenInteractive = DEFAULT_TRACK_SCREEN_INTERACTIVE;
private CachedDeviceState.Readonly mDeviceState;
private CachedDeviceState.TimeInStateStopwatch mBatteryStopwatch;
@@ -160,7 +164,12 @@ public class BinderCallsStats implements BinderInternal.Observer {
duration = 0;
latencyDuration = 0;
}
- final int callingUid = getCallingUid();
+ final boolean screenInteractive = mTrackScreenInteractive
+ ? mDeviceState.isScreenInteractive()
+ : OVERFLOW_SCREEN_INTERACTIVE;
+ final int callingUid = mTrackDirectCallingUid
+ ? getCallingUid()
+ : OVERFLOW_DIRECT_CALLING_UID;
synchronized (mLock) {
// This was already checked in #callStart but check again while synchronized.
@@ -177,7 +186,7 @@ public class BinderCallsStats implements BinderInternal.Observer {
final CallStat callStat = uidEntry.getOrCreate(
callingUid, s.binderClass, s.transactionCode,
- mDeviceState.isScreenInteractive(),
+ screenInteractive,
mCallStatsCount >= mMaxBinderCallStatsCount);
final boolean isNewCallStat = callStat.callCount == 0;
if (isNewCallStat) {
@@ -484,6 +493,30 @@ public class BinderCallsStats implements BinderInternal.Observer {
}
}
+ /**
+ * Whether to track the screen state.
+ */
+ public void setTrackScreenInteractive(boolean enabled) {
+ synchronized (mLock) {
+ if (enabled != mTrackScreenInteractive) {
+ mTrackScreenInteractive = enabled;
+ reset();
+ }
+ }
+ }
+
+ /**
+ * Whether to track direct caller uid.
+ */
+ public void setTrackDirectCallerUid(boolean enabled) {
+ synchronized (mLock) {
+ if (enabled != mTrackDirectCallingUid) {
+ mTrackDirectCallingUid = enabled;
+ reset();
+ }
+ }
+ }
+
public void setAddDebugEntries(boolean addDebugEntries) {
mAddDebugEntries = addDebugEntries;
}
diff --git a/core/java/com/android/internal/os/ChildZygoteInit.java b/core/java/com/android/internal/os/ChildZygoteInit.java
index cc74863632dd..1f816c18f886 100644
--- a/core/java/com/android/internal/os/ChildZygoteInit.java
+++ b/core/java/com/android/internal/os/ChildZygoteInit.java
@@ -102,7 +102,7 @@ public class ChildZygoteInit {
// are just isolated UIDs in the range, because for the webview zygote, there is no
// single range that captures all possible isolated UIDs.
// TODO(b/123615476) narrow this down
- if (uidGidMin < Process.FIRST_ISOLATED_UID) {
+ if (uidGidMin < Process.FIRST_APP_ZYGOTE_ISOLATED_UID) {
throw new RuntimeException("Passed in UID range does not map to isolated processes.");
}
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReader.java b/core/java/com/android/internal/os/KernelCpuThreadReader.java
index b1328e862273..6bbfc2b1277a 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReader.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReader.java
@@ -109,6 +109,12 @@ public class KernelCpuThreadReader {
private Predicate<Integer> mUidPredicate;
/**
+ * If a thread has strictly less than {@code minimumTotalCpuUsageMillis} total CPU usage, it
+ * will not be reported
+ */
+ private int mMinimumTotalCpuUsageMillis;
+
+ /**
* Where the proc filesystem is mounted
*/
private final Path mProcPath;
@@ -142,10 +148,12 @@ public class KernelCpuThreadReader {
public KernelCpuThreadReader(
int numBuckets,
Predicate<Integer> uidPredicate,
+ int minimumTotalCpuUsageMillis,
Path procPath,
Path initialTimeInStatePath,
Injector injector) throws IOException {
mUidPredicate = uidPredicate;
+ mMinimumTotalCpuUsageMillis = minimumTotalCpuUsageMillis;
mProcPath = procPath;
mProcTimeInStateReader = new ProcTimeInStateReader(initialTimeInStatePath);
mInjector = injector;
@@ -158,11 +166,13 @@ public class KernelCpuThreadReader {
* @return the reader, null if an exception was thrown during creation
*/
@Nullable
- public static KernelCpuThreadReader create(int numBuckets, Predicate<Integer> uidPredicate) {
+ public static KernelCpuThreadReader create(
+ int numBuckets, Predicate<Integer> uidPredicate, int minimumTotalCpuUsageMillis) {
try {
return new KernelCpuThreadReader(
numBuckets,
uidPredicate,
+ minimumTotalCpuUsageMillis,
DEFAULT_PROC_PATH,
DEFAULT_INITIAL_TIME_IN_STATE_PATH,
new Injector());
@@ -308,6 +318,18 @@ public class KernelCpuThreadReader {
}
/**
+ * If a thread has strictly less than {@code minimumTotalCpuUsageMillis} total CPU usage, it
+ * will not be reported
+ */
+ void setMinimumTotalCpuUsageMillis(int minimumTotalCpuUsageMillis) {
+ if (minimumTotalCpuUsageMillis < 0) {
+ Slog.w(TAG, "Negative minimumTotalCpuUsageMillis: " + minimumTotalCpuUsageMillis);
+ return;
+ }
+ mMinimumTotalCpuUsageMillis = minimumTotalCpuUsageMillis;
+ }
+
+ /**
* Get the CPU frequencies that correspond to the times reported in
* {@link ThreadCpuUsage#usageTimesMillis}
*/
@@ -346,6 +368,15 @@ public class KernelCpuThreadReader {
}
int[] cpuUsages = mFrequencyBucketCreator.getBucketedValues(cpuUsagesLong);
+ // Check if the total CPU usage below the threshold
+ int totalCpuUsage = 0;
+ for (int i = 0; i < cpuUsages.length; i++) {
+ totalCpuUsage += cpuUsages[i];
+ }
+ if (totalCpuUsage < mMinimumTotalCpuUsageMillis) {
+ return null;
+ }
+
return new ThreadCpuUsage(threadId, threadName, cpuUsages);
}
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java b/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
index 77f6a17acdc9..718bcb43bd9a 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
@@ -59,6 +59,13 @@ public class KernelCpuThreadReaderSettingsObserver extends ContentObserver {
private static final String COLLECTED_UIDS_SETTINGS_KEY = "collected_uids";
private static final String COLLECTED_UIDS_DEFAULT = "1000-1000";
+ /**
+ * Minimum total CPU usage to report
+ */
+ private static final String MINIMUM_TOTAL_CPU_USAGE_MILLIS_SETTINGS_KEY =
+ "minimum_total_cpu_usage_millis";
+ private static final int MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT = 0;
+
private final Context mContext;
@Nullable
@@ -87,7 +94,8 @@ public class KernelCpuThreadReaderSettingsObserver extends ContentObserver {
mContext = context;
mKernelCpuThreadReader = KernelCpuThreadReader.create(
NUM_BUCKETS_DEFAULT,
- UidPredicate.fromString(COLLECTED_UIDS_DEFAULT));
+ UidPredicate.fromString(COLLECTED_UIDS_DEFAULT),
+ MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT);
}
@Override
@@ -124,6 +132,9 @@ public class KernelCpuThreadReaderSettingsObserver extends ContentObserver {
mKernelCpuThreadReader.setNumBuckets(
parser.getInt(NUM_BUCKETS_SETTINGS_KEY, NUM_BUCKETS_DEFAULT));
mKernelCpuThreadReader.setUidPredicate(uidPredicate);
+ mKernelCpuThreadReader.setMinimumTotalCpuUsageMillis(parser.getInt(
+ MINIMUM_TOTAL_CPU_USAGE_MILLIS_SETTINGS_KEY,
+ MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT));
}
/**
diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java
index b3d9ca7670b5..c059721eb2d3 100644
--- a/core/java/com/android/internal/os/LooperStats.java
+++ b/core/java/com/android/internal/os/LooperStats.java
@@ -39,6 +39,7 @@ import java.util.concurrent.ThreadLocalRandom;
public class LooperStats implements Looper.Observer {
public static final String DEBUG_ENTRY_PREFIX = "__DEBUG_";
private static final int SESSION_POOL_SIZE = 50;
+ private static final boolean DISABLED_SCREEN_STATE_TRACKING_VALUE = false;
@GuardedBy("mLock")
private final SparseArray<Entry> mEntries = new SparseArray<>(512);
@@ -54,6 +55,7 @@ public class LooperStats implements Looper.Observer {
private long mStartCurrentTime = System.currentTimeMillis();
private long mStartElapsedTime = SystemClock.elapsedRealtime();
private boolean mAddDebugEntries = false;
+ private boolean mTrackScreenInteractive = false;
public LooperStats(int samplingInterval, int entriesSizeCap) {
this.mSamplingInterval = samplingInterval;
@@ -218,9 +220,15 @@ public class LooperStats implements Looper.Observer {
mSamplingInterval = samplingInterval;
}
+ public void setTrackScreenInteractive(boolean enabled) {
+ mTrackScreenInteractive = enabled;
+ }
+
@Nullable
private Entry findEntry(Message msg, boolean allowCreateNew) {
- final boolean isInteractive = mDeviceState.isScreenInteractive();
+ final boolean isInteractive = mTrackScreenInteractive
+ ? mDeviceState.isScreenInteractive()
+ : DISABLED_SCREEN_STATE_TRACKING_VALUE;
final int id = Entry.idFor(msg, isInteractive);
Entry entry;
synchronized (mLock) {
diff --git a/core/java/com/android/internal/os/RailStats.java b/core/java/com/android/internal/os/RailStats.java
new file mode 100644
index 000000000000..ff0083138b30
--- /dev/null
+++ b/core/java/com/android/internal/os/RailStats.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.os;
+
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import java.util.Map;
+
+/** Rail Stats Power Monitoring Class */
+public final class RailStats {
+ private static final String TAG = "RailStats";
+
+ private static final String WIFI_SUBSYSTEM = "wifi";
+ private static final String CELLULAR_SUBSYSTEM = "cellular";
+
+ private Map<Long, RailInfoData> mRailInfoData = new ArrayMap<>();
+
+ private long mCellularTotalEnergyUseduWs = 0;
+ private long mWifiTotalEnergyUseduWs = 0;
+ private boolean mRailStatsAvailability = true;
+
+ /** Updates the rail data map of all power monitor rails being monitored
+ * Function is called from native side
+ * @param index
+ * @param railName
+ * @param subSystemName
+ * @param timestampSinceBootMs
+ * @param energyUsedSinceBootuWs
+ */
+ public void updateRailData(long index, String railName, String subSystemName,
+ long timestampSinceBootMs, long energyUsedSinceBootuWs) {
+ if (!(subSystemName.equals(WIFI_SUBSYSTEM) || subSystemName.equals(CELLULAR_SUBSYSTEM))) {
+ return;
+ }
+ RailInfoData node = mRailInfoData.get(index);
+ if (node == null) {
+ mRailInfoData.put(index, new RailInfoData(index, railName, subSystemName,
+ timestampSinceBootMs, energyUsedSinceBootuWs));
+ if (subSystemName.equals(WIFI_SUBSYSTEM)) {
+ mWifiTotalEnergyUseduWs += energyUsedSinceBootuWs;
+ return;
+ }
+ if (subSystemName.equals(CELLULAR_SUBSYSTEM)) {
+ mCellularTotalEnergyUseduWs += energyUsedSinceBootuWs;
+ }
+ return;
+ }
+ long timeSinceLastLogMs = timestampSinceBootMs - node.timestampSinceBootMs;
+ long energyUsedSinceLastLoguWs = energyUsedSinceBootuWs - node.energyUsedSinceBootuWs;
+ if (timeSinceLastLogMs < 0 || energyUsedSinceLastLoguWs < 0) {
+ energyUsedSinceLastLoguWs = node.energyUsedSinceBootuWs;
+ }
+ node.timestampSinceBootMs = timestampSinceBootMs;
+ node.energyUsedSinceBootuWs = energyUsedSinceBootuWs;
+ if (subSystemName.equals(WIFI_SUBSYSTEM)) {
+ mWifiTotalEnergyUseduWs += energyUsedSinceLastLoguWs;
+ return;
+ }
+ if (subSystemName.equals(CELLULAR_SUBSYSTEM)) {
+ mCellularTotalEnergyUseduWs += energyUsedSinceLastLoguWs;
+ }
+ }
+
+ /** resets the cellular total energy used aspect.
+ */
+ public void resetCellularTotalEnergyUsed() {
+ mCellularTotalEnergyUseduWs = 0;
+ }
+
+ /** resets the wifi total energy used aspect.
+ */
+ public void resetWifiTotalEnergyUsed() {
+ mWifiTotalEnergyUseduWs = 0;
+ }
+
+ public long getCellularTotalEnergyUseduWs() {
+ return mCellularTotalEnergyUseduWs;
+ }
+
+ public long getWifiTotalEnergyUseduWs() {
+ return mWifiTotalEnergyUseduWs;
+ }
+
+ /** reset the total energy subsystems
+ *
+ */
+ public void reset() {
+ mCellularTotalEnergyUseduWs = 0;
+ mWifiTotalEnergyUseduWs = 0;
+ }
+
+ public RailStats getRailStats() {
+ return this;
+ }
+
+ public void setRailStatsAvailability(boolean railStatsAvailability) {
+ mRailStatsAvailability = railStatsAvailability;
+ }
+
+ public boolean isRailStatsAvailable() {
+ return mRailStatsAvailability;
+ }
+
+ /** Container class to contain rail data information */
+ public static class RailInfoData {
+ private static final String TAG = "RailInfoData";
+ public long index;
+ public String railName;
+ public String subSystemName;
+ public long timestampSinceBootMs;
+ public long energyUsedSinceBootuWs;
+
+ private RailInfoData(long index, String railName, String subSystemName,
+ long timestampSinceBootMs, long energyUsedSinceBoot) {
+ this.index = index;
+ this.railName = railName;
+ this.subSystemName = subSystemName;
+ this.timestampSinceBootMs = timestampSinceBootMs;
+ this.energyUsedSinceBootuWs = energyUsedSinceBoot;
+ }
+
+ /** print the rail data
+ *
+ */
+ public void printData() {
+ Slog.d(TAG, "Index = " + index);
+ Slog.d(TAG, "RailName = " + railName);
+ Slog.d(TAG, "SubSystemName = " + subSystemName);
+ Slog.d(TAG, "TimestampSinceBootMs = " + timestampSinceBootMs);
+ Slog.d(TAG, "EnergyUsedSinceBootuWs = " + energyUsedSinceBootuWs);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/util/ImageUtils.java b/core/java/com/android/internal/util/ImageUtils.java
index 195ae52ce977..274a5136d8e9 100644
--- a/core/java/com/android/internal/util/ImageUtils.java
+++ b/core/java/com/android/internal/util/ImageUtils.java
@@ -16,20 +16,25 @@
package com.android.internal.util;
+import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
-import android.graphics.BitmapFactory;
import android.graphics.Canvas;
+import android.graphics.ImageDecoder;
+import android.graphics.ImageDecoder.ImageInfo;
+import android.graphics.ImageDecoder.Source;
import android.graphics.Matrix;
import android.graphics.Paint;
+import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.os.Bundle;
+import android.util.Size;
import java.io.IOException;
-import java.io.InputStream;
/**
* Utility class for image analysis and processing.
@@ -166,21 +171,18 @@ public class ImageUtils {
/**
* @see https://developer.android.com/topic/performance/graphics/load-bitmap
*/
- public static int calculateInSampleSize(BitmapFactory.Options options,
- int reqWidth, int reqHeight) {
- // Raw height and width of image
- final int height = options.outHeight;
- final int width = options.outWidth;
+ public static int calculateSampleSize(Size currentSize, Size requestedSize) {
int inSampleSize = 1;
- if (height > reqHeight || width > reqWidth) {
- final int halfHeight = height / 2;
- final int halfWidth = width / 2;
+ if (currentSize.getHeight() > requestedSize.getHeight()
+ || currentSize.getWidth() > requestedSize.getWidth()) {
+ final int halfHeight = currentSize.getHeight() / 2;
+ final int halfWidth = currentSize.getWidth() / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
- while ((halfHeight / inSampleSize) >= reqHeight
- && (halfWidth / inSampleSize) >= reqWidth) {
+ while ((halfHeight / inSampleSize) >= requestedSize.getHeight()
+ && (halfWidth / inSampleSize) >= requestedSize.getWidth()) {
inSampleSize *= 2;
}
}
@@ -190,27 +192,27 @@ public class ImageUtils {
/**
* Load a bitmap, and attempt to downscale to the required size, to save
- * on memory.
+ * on memory. Updated to use newer and more compatible ImageDecoder.
*
* @see https://developer.android.com/topic/performance/graphics/load-bitmap
*/
- public static Bitmap decodeSampledBitmapFromStream(ContentResolver resolver,
- Uri uri, int reqWidth, int reqHeight) throws IOException {
-
- final BitmapFactory.Options options = new BitmapFactory.Options();
- try (InputStream is = resolver.openInputStream(uri)) {
- // First decode with inJustDecodeBounds=true to check dimensions
- options.inJustDecodeBounds = true;
- BitmapFactory.decodeStream(is, null, options);
-
- options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
- }
-
- // need to do this twice as the InputStream is consumed in the first call,
- // and not all InputStreams support marks
- try (InputStream is = resolver.openInputStream(uri)) {
- options.inJustDecodeBounds = false;
- return BitmapFactory.decodeStream(is, null, options);
+ public static Bitmap loadThumbnail(ContentResolver resolver, Uri uri, Size size)
+ throws IOException {
+
+ try (ContentProviderClient client = resolver.acquireContentProviderClient(uri)) {
+ final Bundle opts = new Bundle();
+ opts.putParcelable(ContentResolver.EXTRA_SIZE, Point.convert(size));
+
+ return ImageDecoder.decodeBitmap(ImageDecoder.createSource(() -> {
+ return client.openTypedAssetFile(uri, "image/*", opts, null);
+ }), (ImageDecoder decoder, ImageInfo info, Source source) -> {
+ decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+
+ final int sample = calculateSampleSize(info.getSize(), size);
+ if (sample > 1) {
+ decoder.setTargetSampleSize(sample);
+ }
+ });
}
}
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 345058bd4f6f..af0b7c307ef6 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -287,8 +287,8 @@ cc_library_shared {
"libsoundtrigger",
"libminikin",
"libprocessgroup",
- "libnativebridge",
- "libnativeloader",
+ "libnativebridge_lazy",
+ "libnativeloader_lazy",
"libmemunreachable",
"libhidlbase",
"libhidltransport",
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index e8172172f5d2..8f007594dd67 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -355,9 +355,16 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
colorType = kN32_SkColorType;
}
+ sk_sp<SkColorSpace> colorSpace;
+ if (colorType == kAlpha_8_SkColorType) {
+ colorSpace = nullptr;
+ } else {
+ colorSpace = GraphicsJNI::getNativeColorSpace(colorSpacePtr);
+ }
+
SkBitmap bitmap;
bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType,
- GraphicsJNI::getNativeColorSpace(colorSpacePtr)));
+ colorSpace));
sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(&bitmap);
if (!nativeBitmap) {
@@ -385,15 +392,17 @@ static bool bitmapCopyTo(SkBitmap* dst, SkColorType dstCT, const SkBitmap& src,
case kRGB_565_SkColorType:
dstInfo = dstInfo.makeAlphaType(kOpaque_SkAlphaType);
break;
- case kRGBA_F16_SkColorType:
- // The caller does not have an opportunity to pass a dst color space. Assume that
- // they want linear sRGB.
- dstInfo = dstInfo.makeColorSpace(SkColorSpace::MakeSRGBLinear());
+ case kAlpha_8_SkColorType:
+ dstInfo = dstInfo.makeColorSpace(nullptr);
break;
default:
break;
}
+ if (!dstInfo.colorSpace() && dstCT != kAlpha_8_SkColorType) {
+ dstInfo = dstInfo.makeColorSpace(SkColorSpace::MakeSRGB());
+ }
+
if (!dst->setInfo(dstInfo)) {
return false;
}
@@ -608,14 +617,6 @@ static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
return static_cast<jint>(bitmap->getGenerationID());
}
-static jboolean Bitmap_isConfigF16(JNIEnv* env, jobject, jlong bitmapHandle) {
- LocalScopedBitmap bitmap(bitmapHandle);
- if (bitmap->info().colorType() == kRGBA_F16_SkColorType) {
- return JNI_TRUE;
- }
- return JNI_FALSE;
-}
-
static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
LocalScopedBitmap bitmap(bitmapHandle);
if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
@@ -684,9 +685,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
const SkAlphaType alphaType = (SkAlphaType)p->readInt32();
const uint32_t colorSpaceSize = p->readUint32();
sk_sp<SkColorSpace> colorSpace;
- if (kRGBA_F16_SkColorType == colorType) {
- colorSpace = SkColorSpace::MakeSRGBLinear();
- } else if (colorSpaceSize > 0) {
+ if (colorSpaceSize > 0) {
if (colorSpaceSize > kMaxColorSpaceSerializedBytes) {
ALOGD("Bitmap_createFromParcel: Serialized SkColorSpace is larger than expected: "
"%d bytes\n", colorSpaceSize);
@@ -811,7 +810,7 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
p->writeInt32(bitmap.colorType());
p->writeInt32(bitmap.alphaType());
SkColorSpace* colorSpace = bitmap.colorSpace();
- if (colorSpace != nullptr && bitmap.colorType() != kRGBA_F16_SkColorType) {
+ if (colorSpace != nullptr) {
sk_sp<SkData> data = colorSpace->serialize();
size_t size = data->size();
p->writeUint32(size);
@@ -924,44 +923,14 @@ static jboolean Bitmap_isSRGBLinear(JNIEnv* env, jobject, jlong bitmapHandle) {
return colorSpace == srgbLinear.get() ? JNI_TRUE : JNI_FALSE;
}
-static jboolean Bitmap_getColorSpace(JNIEnv* env, jobject, jlong bitmapHandle,
- jfloatArray xyzArray, jfloatArray paramsArray) {
-
+static jobject Bitmap_computeColorSpace(JNIEnv* env, jobject, jlong bitmapHandle) {
LocalScopedBitmap bitmapHolder(bitmapHandle);
- if (!bitmapHolder.valid()) return JNI_FALSE;
+ if (!bitmapHolder.valid()) return nullptr;
SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
- if (colorSpace == nullptr) return JNI_FALSE;
-
- skcms_Matrix3x3 xyzMatrix;
- if (!colorSpace->toXYZD50(&xyzMatrix)) return JNI_FALSE;
-
- jfloat* xyz = env->GetFloatArrayElements(xyzArray, NULL);
- xyz[0] = xyzMatrix.vals[0][0];
- xyz[1] = xyzMatrix.vals[1][0];
- xyz[2] = xyzMatrix.vals[2][0];
- xyz[3] = xyzMatrix.vals[0][1];
- xyz[4] = xyzMatrix.vals[1][1];
- xyz[5] = xyzMatrix.vals[2][1];
- xyz[6] = xyzMatrix.vals[0][2];
- xyz[7] = xyzMatrix.vals[1][2];
- xyz[8] = xyzMatrix.vals[2][2];
- env->ReleaseFloatArrayElements(xyzArray, xyz, 0);
-
- skcms_TransferFunction transferParams;
- if (!colorSpace->isNumericalTransferFn(&transferParams)) return JNI_FALSE;
-
- jfloat* params = env->GetFloatArrayElements(paramsArray, NULL);
- params[0] = transferParams.a;
- params[1] = transferParams.b;
- params[2] = transferParams.c;
- params[3] = transferParams.d;
- params[4] = transferParams.e;
- params[5] = transferParams.f;
- params[6] = transferParams.g;
- env->ReleaseFloatArrayElements(paramsArray, params, 0);
+ if (colorSpace == nullptr) return nullptr;
- return JNI_TRUE;
+ return GraphicsJNI::getColorSpace(env, colorSpace, bitmapHolder->info().colorType());
}
static void Bitmap_setColorSpace(JNIEnv* env, jobject, jlong bitmapHandle, jlong colorSpacePtr) {
@@ -1174,13 +1143,6 @@ static jobject Bitmap_createGraphicBufferHandle(JNIEnv* env, jobject, jlong bitm
return createJavaGraphicBuffer(env, buffer);
}
-static void Bitmap_copyColorSpace(JNIEnv* env, jobject, jlong srcBitmapPtr, jlong dstBitmapPtr) {
- LocalScopedBitmap srcBitmapHandle(srcBitmapPtr);
- LocalScopedBitmap dstBitmapHandle(dstBitmapPtr);
-
- dstBitmapHandle->bitmap().setColorSpace(srcBitmapHandle->bitmap().info().refColorSpace());
-}
-
static jboolean Bitmap_isImmutable(jlong bitmapHandle) {
LocalScopedBitmap bitmapHolder(bitmapHandle);
if (!bitmapHolder.valid()) return JNI_FALSE;
@@ -1215,7 +1177,6 @@ static const JNINativeMethod gBitmapMethods[] = {
{ "nativeErase", "(JJJ)V", (void*)Bitmap_eraseLong },
{ "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes },
{ "nativeConfig", "(J)I", (void*)Bitmap_config },
- { "nativeIsConfigF16", "(J)Z", (void*)Bitmap_isConfigF16 },
{ "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha },
{ "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied},
{ "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha},
@@ -1248,12 +1209,10 @@ static const JNINativeMethod gBitmapMethods[] = {
(void*) Bitmap_wrapHardwareBufferBitmap },
{ "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;",
(void*) Bitmap_createGraphicBufferHandle },
- { "nativeGetColorSpace", "(J[F[F)Z", (void*)Bitmap_getColorSpace },
+ { "nativeComputeColorSpace", "(J)Landroid/graphics/ColorSpace;", (void*)Bitmap_computeColorSpace },
{ "nativeSetColorSpace", "(JJ)V", (void*)Bitmap_setColorSpace },
{ "nativeIsSRGB", "(J)Z", (void*)Bitmap_isSRGB },
{ "nativeIsSRGBLinear", "(J)Z", (void*)Bitmap_isSRGBLinear},
- { "nativeCopyColorSpace", "(JJ)V",
- (void*)Bitmap_copyColorSpace },
{ "nativeSetImmutable", "(J)V", (void*)Bitmap_setImmutable},
// ------------ @CriticalNative ----------------
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 70e6604fddeb..4ba4540f7dbc 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -307,7 +307,7 @@ static jobject doDecode(JNIEnv* env, std::unique_ptr<SkStreamRewindable> stream,
env->SetObjectField(options, gOptions_outConfigFieldID, config);
env->SetObjectField(options, gOptions_outColorSpaceFieldID,
- GraphicsJNI::getColorSpace(env, decodeColorSpace, decodeColorType));
+ GraphicsJNI::getColorSpace(env, decodeColorSpace.get(), decodeColorType));
if (onlyDecodeSize) {
return nullptr;
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index d65f324d1065..9c07e2d64c6e 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -215,7 +215,7 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in
env->SetObjectField(options, gOptions_outConfigFieldID, config);
env->SetObjectField(options, gOptions_outColorSpaceFieldID,
- GraphicsJNI::getColorSpace(env, decodeColorSpace, decodeColorType));
+ GraphicsJNI::getColorSpace(env, decodeColorSpace.get(), decodeColorType));
}
// If we may have reused a bitmap, we need to indicate that the pixels have changed.
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 6570992b4b23..2987c5ed56b5 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -187,6 +187,8 @@ static jmethodID gColorSpaceRGB_constructorMethodID;
static jclass gColorSpace_Named_class;
static jfieldID gColorSpace_Named_sRGBFieldID;
+static jfieldID gColorSpace_Named_ExtendedSRGBFieldID;
+static jfieldID gColorSpace_Named_LinearSRGBFieldID;
static jfieldID gColorSpace_Named_LinearExtendedSRGBFieldID;
static jclass gTransferParameters_class;
@@ -412,67 +414,78 @@ jobject GraphicsJNI::createRegion(JNIEnv* env, SkRegion* region)
///////////////////////////////////////////////////////////////////////////////
-jobject GraphicsJNI::getColorSpace(JNIEnv* env, sk_sp<SkColorSpace>& decodeColorSpace,
+jobject GraphicsJNI::getColorSpace(JNIEnv* env, SkColorSpace* decodeColorSpace,
SkColorType decodeColorType) {
- jobject colorSpace = nullptr;
+ if (!decodeColorSpace || decodeColorType == kAlpha_8_SkColorType) {
+ return nullptr;
+ }
- // No need to match, we know what the output color space will be
+ // Special checks for the common sRGB cases and their extended variants.
+ jobject namedCS = nullptr;
+ sk_sp<SkColorSpace> srgbLinear = SkColorSpace::MakeSRGBLinear();
if (decodeColorType == kRGBA_F16_SkColorType) {
- jobject linearExtendedSRGB = env->GetStaticObjectField(
- gColorSpace_Named_class, gColorSpace_Named_LinearExtendedSRGBFieldID);
- colorSpace = env->CallStaticObjectMethod(gColorSpace_class,
- gColorSpace_getMethodID, linearExtendedSRGB);
- } else {
- // Same here, no need to match
+ // An F16 Bitmap will always report that it is EXTENDED if
+ // it matches a ColorSpace that has an EXTENDED variant.
if (decodeColorSpace->isSRGB()) {
- jobject sRGB = env->GetStaticObjectField(
- gColorSpace_Named_class, gColorSpace_Named_sRGBFieldID);
- colorSpace = env->CallStaticObjectMethod(gColorSpace_class,
- gColorSpace_getMethodID, sRGB);
- } else if (decodeColorSpace.get() != nullptr) {
- // Try to match against known RGB color spaces using the CIE XYZ D50
- // conversion matrix and numerical transfer function parameters
- skcms_Matrix3x3 xyzMatrix;
- LOG_ALWAYS_FATAL_IF(!decodeColorSpace->toXYZD50(&xyzMatrix));
-
- skcms_TransferFunction transferParams;
- // We can only handle numerical transfer functions at the moment
- LOG_ALWAYS_FATAL_IF(!decodeColorSpace->isNumericalTransferFn(&transferParams));
-
- jobject params = env->NewObject(gTransferParameters_class,
- gTransferParameters_constructorMethodID,
- transferParams.a, transferParams.b, transferParams.c,
- transferParams.d, transferParams.e, transferParams.f,
- transferParams.g);
-
- jfloatArray xyzArray = env->NewFloatArray(9);
- jfloat xyz[9] = {
- xyzMatrix.vals[0][0],
- xyzMatrix.vals[1][0],
- xyzMatrix.vals[2][0],
- xyzMatrix.vals[0][1],
- xyzMatrix.vals[1][1],
- xyzMatrix.vals[2][1],
- xyzMatrix.vals[0][2],
- xyzMatrix.vals[1][2],
- xyzMatrix.vals[2][2]
- };
- env->SetFloatArrayRegion(xyzArray, 0, 9, xyz);
-
- colorSpace = env->CallStaticObjectMethod(gColorSpace_class,
- gColorSpace_matchMethodID, xyzArray, params);
-
- if (colorSpace == nullptr) {
- // We couldn't find an exact match, let's create a new color space
- // instance with the 3x3 conversion matrix and transfer function
- colorSpace = env->NewObject(gColorSpaceRGB_class,
- gColorSpaceRGB_constructorMethodID,
- env->NewStringUTF("Unknown"), xyzArray, params);
- }
-
- env->DeleteLocalRef(xyzArray);
+ namedCS = env->GetStaticObjectField(gColorSpace_Named_class,
+ gColorSpace_Named_ExtendedSRGBFieldID);
+ } else if (decodeColorSpace == srgbLinear.get()) {
+ namedCS = env->GetStaticObjectField(gColorSpace_Named_class,
+ gColorSpace_Named_LinearExtendedSRGBFieldID);
}
+ } else if (decodeColorSpace->isSRGB()) {
+ namedCS = env->GetStaticObjectField(gColorSpace_Named_class,
+ gColorSpace_Named_sRGBFieldID);
+ } else if (decodeColorSpace == srgbLinear.get()) {
+ namedCS = env->GetStaticObjectField(gColorSpace_Named_class,
+ gColorSpace_Named_LinearSRGBFieldID);
+ }
+
+ if (namedCS) {
+ return env->CallStaticObjectMethod(gColorSpace_class, gColorSpace_getMethodID, namedCS);
}
+
+ // Try to match against known RGB color spaces using the CIE XYZ D50
+ // conversion matrix and numerical transfer function parameters
+ skcms_Matrix3x3 xyzMatrix;
+ LOG_ALWAYS_FATAL_IF(!decodeColorSpace->toXYZD50(&xyzMatrix));
+
+ skcms_TransferFunction transferParams;
+ // We can only handle numerical transfer functions at the moment
+ LOG_ALWAYS_FATAL_IF(!decodeColorSpace->isNumericalTransferFn(&transferParams));
+
+ jobject params = env->NewObject(gTransferParameters_class,
+ gTransferParameters_constructorMethodID,
+ transferParams.a, transferParams.b, transferParams.c,
+ transferParams.d, transferParams.e, transferParams.f,
+ transferParams.g);
+
+ jfloatArray xyzArray = env->NewFloatArray(9);
+ jfloat xyz[9] = {
+ xyzMatrix.vals[0][0],
+ xyzMatrix.vals[1][0],
+ xyzMatrix.vals[2][0],
+ xyzMatrix.vals[0][1],
+ xyzMatrix.vals[1][1],
+ xyzMatrix.vals[2][1],
+ xyzMatrix.vals[0][2],
+ xyzMatrix.vals[1][2],
+ xyzMatrix.vals[2][2]
+ };
+ env->SetFloatArrayRegion(xyzArray, 0, 9, xyz);
+
+ jobject colorSpace = env->CallStaticObjectMethod(gColorSpace_class,
+ gColorSpace_matchMethodID, xyzArray, params);
+
+ if (colorSpace == nullptr) {
+ // We couldn't find an exact match, let's create a new color space
+ // instance with the 3x3 conversion matrix and transfer function
+ colorSpace = env->NewObject(gColorSpaceRGB_class,
+ gColorSpaceRGB_constructorMethodID,
+ env->NewStringUTF("Unknown"), xyzArray, params);
+ }
+
+ env->DeleteLocalRef(xyzArray);
return colorSpace;
}
@@ -658,6 +671,10 @@ int register_android_graphics_Graphics(JNIEnv* env)
FindClassOrDie(env, "android/graphics/ColorSpace$Named"));
gColorSpace_Named_sRGBFieldID = GetStaticFieldIDOrDie(env,
gColorSpace_Named_class, "SRGB", "Landroid/graphics/ColorSpace$Named;");
+ gColorSpace_Named_ExtendedSRGBFieldID = GetStaticFieldIDOrDie(env,
+ gColorSpace_Named_class, "EXTENDED_SRGB", "Landroid/graphics/ColorSpace$Named;");
+ gColorSpace_Named_LinearSRGBFieldID = GetStaticFieldIDOrDie(env,
+ gColorSpace_Named_class, "LINEAR_SRGB", "Landroid/graphics/ColorSpace$Named;");
gColorSpace_Named_LinearExtendedSRGBFieldID = GetStaticFieldIDOrDie(env,
gColorSpace_Named_class, "LINEAR_EXTENDED_SRGB", "Landroid/graphics/ColorSpace$Named;");
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index dc0d022d94c0..f80651c30d64 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -109,7 +109,13 @@ public:
*/
static sk_sp<SkColorSpace> getNativeColorSpace(jlong colorSpaceHandle);
- static jobject getColorSpace(JNIEnv* env, sk_sp<SkColorSpace>& decodeColorSpace,
+ /**
+ * Return the android.graphics.ColorSpace Java object that corresponds to decodeColorSpace
+ * and decodeColorType.
+ *
+ * This may create a new object if none of the Named ColorSpaces match.
+ */
+ static jobject getColorSpace(JNIEnv* env, SkColorSpace* decodeColorSpace,
SkColorType decodeColorType);
/**
diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp
index 2d83ac320733..9efcace06be3 100644
--- a/core/jni/android/graphics/ImageDecoder.cpp
+++ b/core/jni/android/graphics/ImageDecoder.cpp
@@ -506,9 +506,9 @@ static jstring ImageDecoder_nGetMimeType(JNIEnv* env, jobject /*clazz*/, jlong n
static jobject ImageDecoder_nGetColorSpace(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
auto* codec = reinterpret_cast<ImageDecoder*>(nativePtr)->mCodec.get();
- auto colorType = codec->computeOutputColorType(codec->getInfo().colorType());
+ auto colorType = codec->computeOutputColorType(kN32_SkColorType);
sk_sp<SkColorSpace> colorSpace = codec->computeOutputColorSpace(colorType);
- return GraphicsJNI::getColorSpace(env, colorSpace, colorType);
+ return GraphicsJNI::getColorSpace(env, colorSpace.get(), colorType);
}
static const JNINativeMethod gImageDecoderMethods[] = {
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index a9d75fd6aff7..15d1944205b6 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -107,6 +107,7 @@ fromEGLHandle(JNIEnv *_env, jmethodID mid, jobject obj) {
if (obj == NULL){
jniThrowException(_env, "java/lang/IllegalArgumentException",
"Object is set to null.");
+ return nullptr;
}
jlong handle = _env->CallLongMethod(obj, mid);
@@ -238,6 +239,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return false;
}
return (jboolean)_returnValue;
}
@@ -335,6 +337,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return false;
}
return (jboolean)_returnValue;
}
@@ -454,6 +457,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return false;
}
return (jboolean)_returnValue;
}
@@ -509,6 +513,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return false;
}
return (jboolean)_returnValue;
}
@@ -582,6 +587,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return nullptr;
}
return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
}
@@ -664,6 +670,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return nullptr;
}
return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
}
@@ -721,6 +728,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return nullptr;
}
return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
}
@@ -731,7 +739,7 @@ android_eglCreatePixmapSurface
(JNIEnv *_env, jobject _this, jobject dpy, jobject config, jint pixmap, jintArray attrib_list_ref, jint offset) {
jniThrowException(_env, "java/lang/UnsupportedOperationException",
"eglCreatePixmapSurface");
- return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, (EGLSurface) 0);
+ return nullptr;
}
/* EGLBoolean eglDestroySurface ( EGLDisplay dpy, EGLSurface surface ) */
@@ -800,6 +808,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return false;
}
return (jboolean)_returnValue;
}
@@ -898,6 +907,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return nullptr;
}
return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
}
@@ -1034,6 +1044,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return nullptr;
}
return toEGLHandle(_env, eglcontextClass, eglcontextConstructor, _returnValue);
}
@@ -1152,6 +1163,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return false;
}
return (jboolean)_returnValue;
}
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index e2e66ceb6fbe..95f99b760382 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -55,6 +55,11 @@ void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appNa
devOptInChars.c_str(), rulesFd_native, rulesOffset, rulesLength);
}
+bool shouldUseAngle_native(JNIEnv* env, jobject clazz, jstring appName) {
+ ScopedUtfChars appNameChars(env, appName);
+ return android::GraphicsEnv::getInstance().shouldUseAngle(appNameChars.c_str());
+}
+
void setLayerPaths_native(JNIEnv* env, jobject clazz, jobject classLoader, jstring layerPaths) {
android::NativeLoaderNamespace* appNamespace = android::FindNativeLoaderNamespaceByClassLoader(
env, classLoader);
@@ -81,6 +86,7 @@ const JNINativeMethod g_methods[] = {
{ "setDriverPath", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPath) },
{ "setGpuStats", "(Ljava/lang/String;Ljava/lang/String;JLjava/lang/String;)V", reinterpret_cast<void*>(setGpuStats_native) },
{ "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/io/FileDescriptor;JJ)V", reinterpret_cast<void*>(setAngleInfo_native) },
+ { "getShouldUseAngle", "(Ljava/lang/String;)Z", reinterpret_cast<void*>(shouldUseAngle_native) },
{ "setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V", reinterpret_cast<void*>(setLayerPaths_native) },
{ "setDebugLayers", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayers_native) },
{ "setDebugLayersGLES", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayersGLES_native) },
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index d493ddfaae13..a212f47c0104 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -104,6 +104,12 @@ static struct configuration_offsets_t {
jfieldID mScreenHeightDpOffset;
} gConfigurationOffsets;
+static struct arraymap_offsets_t {
+ jclass classObject;
+ jmethodID constructor;
+ jmethodID put;
+} gArrayMapOffsets;
+
jclass g_stringClass = nullptr;
// ----------------------------------------------------------------------------
@@ -326,6 +332,50 @@ static Guarded<AssetManager2>& AssetManagerFromLong(jlong ptr) {
return *AssetManagerForNdkAssetManager(reinterpret_cast<AAssetManager*>(ptr));
}
+static jobject NativeGetOverlayableMap(JNIEnv* env, jclass /*clazz*/, jlong ptr,
+ jstring package_name) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ const ScopedUtfChars package_name_utf8(env, package_name);
+ CHECK(package_name_utf8.c_str() != nullptr);
+ const std::string std_package_name(package_name_utf8.c_str());
+ const std::unordered_map<std::string, std::string>* map = nullptr;
+
+ assetmanager->ForEachPackage([&](const std::string& this_package_name, uint8_t package_id) {
+ if (this_package_name == std_package_name) {
+ map = assetmanager->GetOverlayableMapForPackage(package_id);
+ }
+ });
+
+ if (map == nullptr) {
+ return nullptr;
+ }
+
+ jobject array_map = env->NewObject(gArrayMapOffsets.classObject, gArrayMapOffsets.constructor);
+ if (array_map == nullptr) {
+ return nullptr;
+ }
+
+ for (const auto& iter : *map) {
+ jstring name = env->NewStringUTF(iter.first.c_str());
+ if (env->ExceptionCheck()) {
+ return nullptr;
+ }
+
+ jstring actor = env->NewStringUTF(iter.second.c_str());
+ if (env->ExceptionCheck()) {
+ env->DeleteLocalRef(name);
+ return nullptr;
+ }
+
+ env->CallObjectMethod(array_map, gArrayMapOffsets.put, name, actor);
+
+ env->DeleteLocalRef(name);
+ env->DeleteLocalRef(actor);
+ }
+
+ return array_map;
+}
+
static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset,
jlongArray out_offsets) {
off64_t start_offset, length;
@@ -1524,6 +1574,8 @@ static const JNINativeMethod gAssetManagerMethods[] = {
{"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps},
{"nativeCreateIdmapsForStaticOverlaysTargetingAndroid", "()[Ljava/lang/String;",
(void*)NativeCreateIdmapsForStaticOverlaysTargetingAndroid},
+ {"nativeGetOverlayableMap", "(JLjava/lang/String;)Ljava/util/Map;",
+ (void*)NativeGetOverlayableMap},
// Global management/debug methods.
{"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
@@ -1575,6 +1627,14 @@ int register_android_content_AssetManager(JNIEnv* env) {
gConfigurationOffsets.mScreenHeightDpOffset =
GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I");
+ jclass arrayMapClass = FindClassOrDie(env, "android/util/ArrayMap");
+ gArrayMapOffsets.classObject = MakeGlobalRefOrDie(env, arrayMapClass);
+ gArrayMapOffsets.constructor =
+ GetMethodIDOrDie(env, gArrayMapOffsets.classObject, "<init>", "()V");
+ gArrayMapOffsets.put =
+ GetMethodIDOrDie(env, gArrayMapOffsets.classObject, "put",
+ "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+
return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
NELEM(gAssetManagerMethods));
}
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 8c7363021d3b..2aa5cb41d5ab 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -33,7 +33,6 @@
#include <private/EGL/cache.h>
-#include <utils/Looper.h>
#include <utils/RefBase.h>
#include <utils/StrongPointer.h>
#include <utils/Timers.h>
@@ -144,52 +143,22 @@ private:
uint32_t mRequestId;
};
-class RenderingException : public MessageHandler {
+class FrameCompleteWrapper : public LightRefBase<FrameCompleteWrapper> {
public:
- RenderingException(JavaVM* vm, const std::string& message)
- : mVm(vm)
- , mMessage(message) {
- }
-
- virtual void handleMessage(const Message&) {
- throwException(mVm, mMessage);
- }
-
- static void throwException(JavaVM* vm, const std::string& message) {
- JNIEnv* env = getenv(vm);
- jniThrowException(env, "java/lang/IllegalStateException", message.c_str());
- }
-
-private:
- JavaVM* mVm;
- std::string mMessage;
-};
-
-class FrameCompleteWrapper : public MessageHandler {
-public:
- FrameCompleteWrapper(JNIEnv* env, jobject jobject) {
- mLooper = Looper::getForThread();
- LOG_ALWAYS_FATAL_IF(!mLooper.get(), "Must create runnable on a Looper thread!");
+ explicit FrameCompleteWrapper(JNIEnv* env, jobject jobject) {
env->GetJavaVM(&mVm);
mObject = env->NewGlobalRef(jobject);
LOG_ALWAYS_FATAL_IF(!mObject, "Failed to make global ref");
}
- virtual ~FrameCompleteWrapper() {
+ ~FrameCompleteWrapper() {
releaseObject();
}
- void postFrameComplete(int64_t frameNr) {
- if (mObject) {
- mFrameNr = frameNr;
- mLooper->sendMessage(this, 0);
- }
- }
-
- virtual void handleMessage(const Message&) {
+ void onFrameComplete(int64_t frameNr) {
if (mObject) {
- ATRACE_FORMAT("frameComplete %" PRId64, mFrameNr);
- getenv(mVm)->CallVoidMethod(mObject, gFrameCompleteCallback.onFrameComplete, mFrameNr);
+ ATRACE_FORMAT("frameComplete %" PRId64, frameNr);
+ getenv(mVm)->CallVoidMethod(mObject, gFrameCompleteCallback.onFrameComplete, frameNr);
releaseObject();
}
}
@@ -197,8 +166,6 @@ public:
private:
JavaVM* mVm;
jobject mObject;
- sp<Looper> mLooper;
- int64_t mFrameNr = -1;
void releaseObject() {
if (mObject) {
@@ -211,16 +178,14 @@ private:
class RootRenderNode : public RenderNode, ErrorHandler {
public:
explicit RootRenderNode(JNIEnv* env) : RenderNode() {
- mLooper = Looper::getForThread();
- LOG_ALWAYS_FATAL_IF(!mLooper.get(),
- "Must create RootRenderNode on a thread with a looper!");
env->GetJavaVM(&mVm);
}
virtual ~RootRenderNode() {}
virtual void onError(const std::string& message) override {
- mLooper->sendMessage(new RenderingException(mVm, message), 0);
+ JNIEnv* env = getenv(mVm);
+ jniThrowException(env, "java/lang/IllegalStateException", message.c_str());
}
virtual void prepareTree(TreeInfo& info) override {
@@ -249,14 +214,6 @@ public:
info.errorHandler = nullptr;
}
- void sendMessage(const sp<MessageHandler>& handler) {
- mLooper->sendMessage(handler, 0);
- }
-
- void sendMessageDelayed(const sp<MessageHandler>& handler, nsecs_t delayInMs) {
- mLooper->sendMessageDelayed(ms2ns(delayInMs), handler, 0);
- }
-
void attachAnimatingNode(RenderNode* animatingNode) {
mPendingAnimatingRenderNodes.push_back(animatingNode);
}
@@ -404,7 +361,6 @@ public:
}
private:
- sp<Looper> mLooper;
JavaVM* mVm;
std::vector< sp<RenderNode> > mPendingAnimatingRenderNodes;
std::set< sp<PropertyValuesAnimatorSet> > mPendingVectorDrawableAnimators;
@@ -435,7 +391,9 @@ private:
// the onFinished callback will then be ignored.
sp<FinishAndInvokeListener> message
= new FinishAndInvokeListener(anim);
- sendMessageDelayed(message, remainingTimeInMs);
+ auto looper = Looper::getForThread();
+ LOG_ALWAYS_FATAL_IF(looper == nullptr, "Not on a looper thread?");
+ looper->sendMessageDelayed(ms2ns(remainingTimeInMs), message, 0);
anim->clearOneShotListener();
}
}
@@ -463,7 +421,6 @@ public:
virtual void runRemainingAnimations(TreeInfo& info) {
AnimationContext::runRemainingAnimations(info);
mRootNode->runVectorDrawableAnimators(this, info);
- postOnFinishedEvents();
}
virtual void pauseAnimators() override {
@@ -471,27 +428,16 @@ public:
}
virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) {
- OnFinishedEvent event(animator, listener);
- mOnFinishedEvents.push_back(event);
+ listener->onAnimationFinished(animator);
}
virtual void destroy() {
AnimationContext::destroy();
mRootNode->detachAnimators();
- postOnFinishedEvents();
}
private:
sp<RootRenderNode> mRootNode;
- std::vector<OnFinishedEvent> mOnFinishedEvents;
-
- void postOnFinishedEvents() {
- if (mOnFinishedEvents.size()) {
- sp<InvokeAnimationListeners> message
- = new InvokeAnimationListeners(mOnFinishedEvents);
- mRootNode->sendMessage(message);
- }
- }
};
class ContextFactoryImpl : public IContextFactory {
@@ -958,7 +904,7 @@ static void android_view_ThreadedRenderer_setFrameCompleteCallback(JNIEnv* env,
} else {
sp<FrameCompleteWrapper> wrapper = new FrameCompleteWrapper{env, callback};
proxy->setFrameCompleteCallback([wrapper](int64_t frameNr) {
- wrapper->postFrameComplete(frameNr);
+ wrapper->onFrameComplete(frameNr);
});
}
}
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index bbe89d60c7f5..5cecf66a593c 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -598,23 +598,31 @@ static int UnmountTree(const char* path) {
return 0;
}
+static void CreateDir(const std::string& dir,
+ mode_t mode, uid_t uid, gid_t gid,
+ fail_fn_t fail_fn) {
+ if (TEMP_FAILURE_RETRY(access(dir.c_str(), F_OK)) == 0) {
+ return;
+ } else if (errno != ENOENT) {
+ fail_fn(CREATE_ERROR("Failed to stat %s: %s", dir.c_str(), strerror(errno)));
+ }
+ if (fs_prepare_dir(dir.c_str(), mode, uid, gid) != 0) {
+ fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s: %s",
+ dir.c_str(), strerror(errno)));
+ }
+}
+
static void CreatePkgSandbox(uid_t uid, const std::string& package_name, fail_fn_t fail_fn) {
// Create /mnt/user/0/package/<package-name>
userid_t user_id = multiuser_get_user_id(uid);
std::string pkg_sandbox_dir = StringPrintf("/mnt/user/%d", user_id);
- if (fs_prepare_dir(pkg_sandbox_dir.c_str(), 0751, AID_ROOT, AID_ROOT) != 0) {
- fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str()));
- }
+ CreateDir(pkg_sandbox_dir, 0751, AID_ROOT, AID_ROOT, fail_fn);
StringAppendF(&pkg_sandbox_dir, "/package");
- if (fs_prepare_dir(pkg_sandbox_dir.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
- fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str()));
- }
+ CreateDir(pkg_sandbox_dir, 0700, AID_ROOT, AID_ROOT, fail_fn);
StringAppendF(&pkg_sandbox_dir, "/%s", package_name.c_str());
- if (fs_prepare_dir(pkg_sandbox_dir.c_str(), 0755, uid, uid) != 0) {
- fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str()));
- }
+ CreateDir(pkg_sandbox_dir, 0700, AID_ROOT, AID_ROOT, fail_fn);
}
static void BindMount(const std::string& sourceDir, const std::string& targetDir,
@@ -629,20 +637,41 @@ static void BindMount(const std::string& sourceDir, const std::string& targetDir
static void MountPkgSpecificDir(const std::string& mntSourceRoot,
const std::string& mntTargetRoot,
const std::string& packageName,
+ uid_t uid,
const char* dirName,
fail_fn_t fail_fn) {
std::string mntSourceDir = StringPrintf("%s/Android/%s/%s",
mntSourceRoot.c_str(), dirName, packageName.c_str());
+ CreateDir(mntSourceDir, 0755, uid, uid, fail_fn);
+
std::string mntTargetDir = StringPrintf("%s/Android/%s/%s",
mntTargetRoot.c_str(), dirName, packageName.c_str());
+ CreateDir(mntTargetDir, 0755, uid, uid, fail_fn);
BindMount(mntSourceDir, mntTargetDir, fail_fn);
}
+
+static void createPkgSpecificDirRoots(const std::string& parentDir,
+ bool createSandbox,
+ mode_t mode, uid_t uid, gid_t gid,
+ fail_fn_t fail_fn) {
+ std::string androidDir = StringPrintf("%s/Android", parentDir.c_str());
+ CreateDir(androidDir, mode, uid, gid, fail_fn);
+ std::vector<std::string> dirs = {"data", "media", "obb"};
+ if (createSandbox) {
+ dirs.push_back("sandbox");
+ }
+ for (auto& dir : dirs) {
+ std::string path = StringPrintf("%s/%s", androidDir.c_str(), dir.c_str());
+ CreateDir(path, mode, uid, gid, fail_fn);
+ }
+}
+
static void PreparePkgSpecificDirs(const std::vector<std::string>& packageNames,
const std::vector<std::string>& volumeLabels,
bool mountAllObbs, const std::string& sandboxId,
- userid_t userId, fail_fn_t fail_fn) {
+ userid_t userId, uid_t uid, fail_fn_t fail_fn) {
for (auto& label : volumeLabels) {
std::string mntSource = StringPrintf("/mnt/runtime/write/%s", label.c_str());
std::string mntTarget = StringPrintf("/storage/%s", label.c_str());
@@ -651,15 +680,26 @@ static void PreparePkgSpecificDirs(const std::vector<std::string>& packageNames,
StringAppendF(&mntTarget, "/%d", userId);
}
+ if (TEMP_FAILURE_RETRY(access(mntSource.c_str(), F_OK)) < 0) {
+ ALOGE("Can't access %s: %s", mntSource.c_str(), strerror(errno));
+ continue;
+ }
+
+ // Create /mnt/runtime/write/emulated/0/Android/{data,media,obb,sandbox}
+ createPkgSpecificDirRoots(mntSource, true, 0700, AID_ROOT, AID_ROOT, fail_fn);
+
std::string sandboxSource = StringPrintf("%s/Android/sandbox/%s",
mntSource.c_str(), sandboxId.c_str());
+ CreateDir(sandboxSource, 0755, uid, uid, fail_fn);
BindMount(sandboxSource, mntTarget, fail_fn);
+ // Create /storage/emulated/0/Android/{data,media,obb}
+ createPkgSpecificDirRoots(mntTarget, false, 0755, uid, uid, fail_fn);
for (auto& package : packageNames) {
- MountPkgSpecificDir(mntSource, mntTarget, package, "data", fail_fn);
- MountPkgSpecificDir(mntSource, mntTarget, package, "media", fail_fn);
+ MountPkgSpecificDir(mntSource, mntTarget, package, uid, "data", fail_fn);
+ MountPkgSpecificDir(mntSource, mntTarget, package, uid, "media", fail_fn);
if (!mountAllObbs) {
- MountPkgSpecificDir(mntSource, mntTarget, package, "obb", fail_fn);
+ MountPkgSpecificDir(mntSource, mntTarget, package, uid, "obb", fail_fn);
}
}
@@ -702,7 +742,7 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode,
return;
}
- if (GetBoolProperty(kIsolatedStorageSnapshot, GetBoolProperty(kIsolatedStorage, false))) {
+ if (GetBoolProperty(kIsolatedStorageSnapshot, GetBoolProperty(kIsolatedStorage, true))) {
if (mount_mode == MOUNT_EXTERNAL_FULL || mount_mode == MOUNT_EXTERNAL_LEGACY) {
storageSource = (mount_mode == MOUNT_EXTERNAL_FULL)
? "/mnt/runtime/full" : "/mnt/runtime/write";
@@ -774,7 +814,7 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode,
// care of by vold later.
if (sandboxAlreadyCreated) {
PreparePkgSpecificDirs(packages_for_uid, visible_vol_ids,
- mount_mode == MOUNT_EXTERNAL_INSTALLER, sandbox_id, user_id, fail_fn);
+ mount_mode == MOUNT_EXTERNAL_INSTALLER, sandbox_id, user_id, uid, fail_fn);
}
}
} else {
diff --git a/core/jni/runtime_native_boot-flags-test.sh b/core/jni/runtime_native_boot-flags-test.sh
new file mode 100755
index 000000000000..66e18bb19c44
--- /dev/null
+++ b/core/jni/runtime_native_boot-flags-test.sh
@@ -0,0 +1,244 @@
+#!/bin/bash
+
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Test Android Runtime (Boot) device configuration flags (living in namespace
+# `runtime_native_boot`).
+
+me=$(basename $0)
+
+# Namespace containing the tested flag.
+namespace=runtime_native_boot
+# Default set of checked zygote processes.
+zygotes=
+
+# Status of whole test script.
+exit_status=0
+
+function say {
+ echo "$me: $*"
+}
+
+function banner {
+ local separator=$(echo "$@" | sed s/./=/g )
+ say "$separator"
+ say "$@"
+ say "$separator"
+}
+
+function fail {
+ say "FAILED: $@"
+ exit_status=1
+}
+
+function reboot_and_wait_for_device {
+ say "Rebooting device..."
+ adb reboot
+ adb wait-for-device >/dev/null
+ # Wait until the device has finished booting. Give the device 60 iterations
+ # (~60 seconds) to try and finish booting before declaring defeat.
+ local niters=60
+ for i in $(seq $niters); do
+ [[ $(adb shell getprop sys.boot_completed) -eq 1 ]] && return 0
+ sleep 1
+ done
+ fail "Device did not finish booting before timeout (~$niters seconds)"
+}
+
+# check_device_config_flag CONTEXT FLAG VALUE
+# -------------------------------------------
+# Check that the device configuration flag FLAG is set to VALUE. Use CONTEXT in
+# logging.
+function check_device_config_flag {
+ local context=$1
+ local flag=$2
+ local value=$3
+
+ say "[$context] Check that the device configuration flag is set..."
+ local flag_value=$(adb shell device_config get "$namespace" "$flag")
+ [[ "$flag_value" = "$value" ]] \
+ || fail "Device configuration flag \`$flag\` set to \`$flag_value\` (expected \`$value\`)"
+}
+
+# check_no_device_config_flag CONTEXT FLAG
+# ----------------------------------------
+# Check that the device configuration flag FLAG is not set. Use CONTEXT in
+# logging.
+function check_no_device_config_flag {
+ local context=$1
+ local flag=$2
+
+ say "[$context] Check that the device configuration flag is not set..."
+ local flag_value=$(adb shell device_config get "$namespace" "$flag")
+ [[ "$flag_value" = null ]] \
+ || fail "Device configuration flag \`$flag\` set to \`$flag_value\` (expected `null`)"
+}
+
+# get_system_property PROP
+# ------------------------
+# Get system property PROP associated with a device configuration flag.
+function get_system_property {
+ local prop=$1
+
+ # Note that we need to be root to read that system property.
+ adb root >/dev/null
+ local prop_value=$(adb shell getprop "$prop")
+ adb unroot >/dev/null
+ echo "$prop_value"
+}
+
+# check_system_property CONTEXT PROP VALUE
+# ----------------------------------------
+# Check that the system property PROP associated with a device configuration
+# flag is set to VALUE. Use CONTEXT in logging.
+function check_system_property {
+ local context=$1
+ local prop=$2
+ local value=$3
+
+ say "[$context] Check that the persistent system property is set..."
+ local prop_value=$(get_system_property "$prop")
+ [[ "$prop_value" = "$value" ]] \
+ || fail "System property \`$prop\` set to \`$prop_value\` (expected \`$value\`)"
+}
+
+# check_no_system_property CONTEXT PROP
+# -------------------------------------
+# Check that the system property PROP associated with a device configuration
+# flag is not set. Use CONTEXT in logging.
+function check_no_system_property {
+ local context=$1
+ local prop=$2
+
+ say "[$context] Check that the persistent system property is not set..."
+ local prop_value=$(get_system_property "$prop")
+ [[ -z "$prop_value" ]] \
+ || fail "System property \`$prop\` set to \`$prop_value\` (expected unset property)"
+}
+
+# find_zygote_runtime_option ZYGOTE RUNTIME_OPTION
+# ------------------------------------------------
+# Return whether ZYGOTE is passed RUNTIME_OPTION.
+function find_zygote_runtime_option {
+ local zygote=$1
+ local runtime_option=$2
+
+ adb logcat -d -s "$zygote" | grep -q -e "option\[[0-9]\+\]=$runtime_option"
+}
+
+# check_zygote_gc_runtime_option CONTEXT VALUE
+# --------------------------------------------
+# Check that all zygote processes are passed device configuration flag VALUE as
+# GC runtime option. Use CONTEXT in logging.
+function check_zygote_gc_runtime_option {
+ local context=$1
+ local value=$2
+
+ say \
+ "[$context] Check that all zygote processes are passed the flag value as a GC runtime option..."
+ local runtime_option="-Xgc:$value"
+ for zygote in $zygotes; do
+ find_zygote_runtime_option "$zygote" "$runtime_option"\
+ || fail "Found no \`$runtime_option\` among runtime options passed to \`$zygote\`"
+ done
+}
+
+# check_no_zygote_gc_runtime_option CONTEXT VALUE
+# -----------------------------------------------
+# Check that no zygote process is passed device configuration flag VALUE as GC
+# runtime option. Use CONTEXT in logging.
+function check_no_zygote_gc_runtime_option {
+ local context=$1
+ local value=$2
+
+ say "[$context] Check no zygote process is passed the flag value as a GC runtime option..."
+ local runtime_option="-Xgc:$value"
+ for zygote in $zygotes; do
+ find_zygote_runtime_option "$zygote" "$runtime_option"\
+ && fail "Found \`$runtime_option\` among runtime options passed to \`$zygote\`"
+ done
+}
+
+# test_android_runtime_flag FLAG VALUE
+# ------------------------------------
+# Test device configuration FLAG with VALUE.
+function test_android_runtime_flag {
+ local flag=$1
+ local value=$2
+
+ # Persistent system property (set after a reboot) associated with the device
+ # configuration flag.
+ local prop="persist.device_config.$namespace.$flag"
+
+ banner "Testing \`$flag\` value \`$value\`."
+
+ say "Setting device configuration flag..."
+ adb shell device_config put "$namespace" "$flag" "$value"
+ # Give some time to the device to digest this change before rebooting.
+ sleep 3
+
+ # Check that both the device configuration flag and the associated system
+ # property are set, but that the zygote hasn't had the flag passed to it as a
+ # GC runtime option (as we haven't rebooted yet).
+ local context="Flag set, before reboot"
+ check_device_config_flag "$context" "$flag" "$value"
+ check_system_property "$context" "$prop" "$value"
+ check_no_zygote_gc_runtime_option "$context" "$value"
+
+ # Reboot device for the flag value to take effect.
+ reboot_and_wait_for_device
+ context="Flag set, after 1st reboot"
+ check_device_config_flag "$context" "$flag" "$value"
+ check_system_property "$context" "$prop" "$value"
+ check_zygote_gc_runtime_option "$context" "$value"
+
+ # Reboot device a second time and check that the state has persisted.
+ reboot_and_wait_for_device
+ context="Flag set, after 2nd reboot"
+ check_device_config_flag "$context" "$flag" "$value"
+ check_system_property "$context" "$prop" "$value"
+ check_zygote_gc_runtime_option "$context" "$value"
+
+ say "Unsetting device configuration flag..."
+ adb shell device_config delete "$namespace" "$flag" >/dev/null
+ # Give some time to the device to digest this change before rebooting.
+ sleep 3
+
+ # Reboot and check that the device is back to its default state.
+ reboot_and_wait_for_device
+ context="Flag unset, after 3rd reboot"
+ check_no_device_config_flag "$context" "$flag"
+ check_no_system_property "$context" "$prop"
+ check_no_zygote_gc_runtime_option "$context" "$value"
+}
+
+# Enumerate Zygote processes.
+case $(adb shell getprop ro.zygote) in
+ (zygote32) zygotes="zygote";;
+ (zygote64) zygotes="zygote64";;
+ (zygote32_64|zygote64_32) zygotes="zygote zygote64";;
+esac
+
+# Test "gctype" flag values.
+test_android_runtime_flag gctype nogenerational_cc
+test_android_runtime_flag gctype generational_cc
+
+if [[ "$exit_status" -eq 0 ]]; then
+ banner "All tests passed."
+else
+ banner "Test(s) failed."
+fi
+exit $exit_status
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 30b9b7847fb6..5497b8665cf0 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -610,6 +610,11 @@ enum Action {
// CATEGORY: SETTINGS
// OS: Q
ACTION_SET_NEW_PARENT_PROFILE_PASSWORD = 1646;
+
+ // ACTION: An interaction with a Slice or other component in the Panel.
+ // CATEGORY: SETTINGS
+ // OS: Q
+ ACTION_PANEL_INTERACTION = 1658;
}
/**
@@ -2214,4 +2219,16 @@ enum PageId {
// CATEGORY: SETTINGS
// OS: Q
SET_NEW_PASSWORD_ACTIVITY = 1644;
+
+ // Panel for Internet Connectivity
+ PANEL_INTERNET_CONNECTIVITY = 1654;
+
+ // Panel for Volume
+ PANEL_VOLUME = 1655;
+
+ // Panel for NFC
+ PANEL_NFC = 1656;
+
+ // Panel for Media Output
+ PANEL_MEDIA_OUTPUT = 1657;
}
diff --git a/core/proto/android/bluetooth/enums.proto b/core/proto/android/bluetooth/enums.proto
index 5b5c9c28b4a0..b4f3d1ea5ae4 100644
--- a/core/proto/android/bluetooth/enums.proto
+++ b/core/proto/android/bluetooth/enums.proto
@@ -132,3 +132,9 @@ enum SocketConnectionstateEnum {
// This socket is closed
SOCKET_CONNECTION_STATE_DISCONNECTED = 5;
}
+
+enum SocketRoleEnum {
+ SOCKET_ROLE_UNKNOWN = 0;
+ SOCKET_ROLE_LISTEN = 1;
+ SOCKET_ROLE_CONNECTION = 2;
+}
diff --git a/core/proto/android/hardware/biometrics/enums.proto b/core/proto/android/hardware/biometrics/enums.proto
index 91f2acbbaf03..973e3e65cf1a 100644
--- a/core/proto/android/hardware/biometrics/enums.proto
+++ b/core/proto/android/hardware/biometrics/enums.proto
@@ -43,4 +43,16 @@ enum ActionEnum {
ACTION_AUTHENTICATE = 2;
ACTION_ENUMERATE = 3;
ACTION_REMOVE = 4;
+}
+
+enum IssueEnum {
+ ISSUE_UNKNOWN = 0;
+ // When a biometric HAL has crashed.
+ ISSUE_HAL_DEATH = 1;
+ // When Android Framework has a template that doesn't exist in the HAL. The framework
+ // is expected to remove its template to stay in sync with the HAL.
+ ISSUE_UNKNOWN_TEMPLATE_ENROLLED_FRAMEWORK = 2;
+ // When the HAL has a template that doesn't exist in Android Framework. The framework
+ // is expected to notify the HAL to remove this template to stay in sync with the framework.
+ ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL = 3;
} \ No newline at end of file
diff --git a/core/proto/android/hardware/sensor/assist/enums.proto b/core/proto/android/hardware/sensor/assist/enums.proto
new file mode 100644
index 000000000000..8c5841a32d54
--- /dev/null
+++ b/core/proto/android/hardware/sensor/assist/enums.proto
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+package android.hardware.sensor.assist;
+
+option java_outer_classname = "AssistGestureProtoEnums";
+option java_multiple_files = true;
+
+enum AssistGestureStageEnum {
+ ASSIST_GESTURE_STAGE_UNKNOWN = 0;
+ ASSIST_GESTURE_STAGE_PROGRESS = 1;
+ ASSIST_GESTURE_STAGE_PRIMED = 2;
+ ASSIST_GESTURE_STAGE_DETECTED = 3;
+}
+
+enum AssistGestureFeedbackEnum {
+ ASSIST_GESTURE_FEEDBACK_UNKNOWN = 0;
+ ASSIST_GESTURE_FEEDBACK_NOT_USED = 1;
+ ASSIST_GESTURE_FEEDBACK_USED = 2;
+} \ No newline at end of file
diff --git a/core/proto/android/os/batterystats.proto b/core/proto/android/os/batterystats.proto
index a4167c187194..516fa7b9336b 100644
--- a/core/proto/android/os/batterystats.proto
+++ b/core/proto/android/os/batterystats.proto
@@ -58,6 +58,10 @@ message ControllerActivityProto {
optional int64 duration_ms = 2;
}
repeated TxLevel tx = 4;
+
+ // Total rail charge consumed by the monitored rails by the controller. The value may
+ // always be 0 if the device doesn't support monitored rail calculations.
+ optional double monitored_rail_charge_mah = 5;
}
message SystemProto {
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index d5776534bb90..c9957f369473 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -448,6 +448,11 @@ message GlobalSettingsProto {
optional SettingProto game_driver_whitelist = 12;
// ANGLE - List of Apps that can check ANGLE rules
optional SettingProto angle_whitelist = 13;
+ // Game Driver - List of blacklists, each blacklist is a blacklist for
+ // a specific Game Driver version
+ optional SettingProto game_driver_blacklists = 14;
+ // ANGLE - Show a dialog box when ANGLE is selected for the currently running PKG
+ optional SettingProto show_angle_in_use_dialog = 15;
}
optional Gpu gpu = 59;
diff --git a/core/proto/android/server/connectivity/Android.bp b/core/proto/android/server/connectivity/Android.bp
new file mode 100644
index 000000000000..c0ac2cb8f800
--- /dev/null
+++ b/core/proto/android/server/connectivity/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_library_static {
+ name: "datastallprotosnano",
+ proto: {
+ type: "nano",
+ },
+ srcs: [
+ "data_stall_event.proto",
+ ],
+ sdk_version: "system_current",
+ no_framework_libs: true,
+} \ No newline at end of file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 34ec92e68511..5b74d90608f7 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2151,13 +2151,13 @@
android:label="@string/permlab_disableKeyguard"
android:protectionLevel="normal" />
- <!-- Allows an application to get the screen lock complexity and prompt users to update the
+ <!-- Allows an application to request the screen lock complexity and prompt users to update the
screen lock to a certain complexity level.
<p>Protection level: normal
-->
- <permission android:name="android.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY"
- android:label="@string/permlab_getAndRequestScreenLockComplexity"
- android:description="@string/permdesc_getAndRequestScreenLockComplexity"
+ <permission android:name="android.permission.REQUEST_SCREEN_LOCK_COMPLEXITY"
+ android:label="@string/permlab_requestScreenLockComplexity"
+ android:description="@string/permdesc_requestScreenLockComplexity"
android:protectionLevel="normal" />
<!-- ================================== -->
diff --git a/core/res/res/drawable/bottomsheet_background.xml b/core/res/res/drawable/bottomsheet_background.xml
index bc32ba6e3896..3a8ad71187a0 100644
--- a/core/res/res/drawable/bottomsheet_background.xml
+++ b/core/res/res/drawable/bottomsheet_background.xml
@@ -16,7 +16,7 @@
<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
<corners
- android:topLeftRadius="?attr/dialogCornerRadius"
- android:topRightRadius="?attr/dialogCornerRadius" />
+ android:topLeftRadius="@dimen/config_bottomDialogCornerRadius"
+ android:topRightRadius="@dimen/config_bottomDialogCornerRadius"/>
<solid android:color="?attr/colorBackgroundFloating" />
</shape>
diff --git a/core/res/res/drawable/ic_action_open.xml b/core/res/res/drawable/ic_action_open.xml
new file mode 100644
index 000000000000..3d3d36ece0af
--- /dev/null
+++ b/core/res/res/drawable/ic_action_open.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/>
+</vector> \ No newline at end of file
diff --git a/core/res/res/drawable/ic_file_copy.xml b/core/res/res/drawable/ic_file_copy.xml
new file mode 100644
index 000000000000..b6d5e7328c40
--- /dev/null
+++ b/core/res/res/drawable/ic_file_copy.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM15,5l6,6v10c0,1.1 -0.9,2 -2,2L7.99,23C6.89,23 6,22.1 6,21l0.01,-14c0,-1.1 0.89,-2 1.99,-2h7zM14,12h5.5L14,6.5L14,12z"
+ android:fillColor="#FF737373"/>
+</vector>
diff --git a/core/res/res/drawable/ic_qs_night_display_on.xml b/core/res/res/drawable/ic_qs_night_display_on.xml
index 35907cc83fe0..a4755ee256e2 100644
--- a/core/res/res/drawable/ic_qs_night_display_on.xml
+++ b/core/res/res/drawable/ic_qs_night_display_on.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2017 The Android Open Source Project
+ Copyright (C) 2019 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,14 +14,13 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="64dp"
- android:height="64dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <group
- android:translateX="-1.0">
- <path
- android:pathData="M13,12c0,-3.57 2.2,-6.62 5.31,-7.87 0.89,-0.36 0.75,-1.69 -0.19,-1.9 -1.1,-0.24 -2.27,-0.3 -3.48,-0.14 -4.51,0.6 -8.12,4.31 -8.59,8.83C5.43,16.93 10.12,22 16,22c0.73,0 1.43,-0.08 2.12,-0.23 0.95,-0.21 1.1,-1.53 0.2,-1.9A8.471,8.471 0,0 1,13 12z"
- android:fillColor="#FFF"/>
- </group>
-</vector> \ No newline at end of file
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M6.28,4.81c0,0.16,0.01,0.32,0.02,0.48c0.38,6.58,5.83,12.03,12.41,12.41c0.16,0.01,0.32,0.02,0.47,0.02 c-1.58,1.2-3.53,1.88-5.56,1.88c-0.46,0-0.93-0.03-1.4-0.1c-3.96-0.58-7.13-3.75-7.71-7.71C4.13,9.24,4.8,6.75,6.28,4.81 M8.27,0.6 c-0.08,0-0.17,0.02-0.25,0.07c-3.8,2.2-6.2,6.56-5.49,11.4c0.7,4.82,4.59,8.7,9.4,9.4c0.57,0.08,1.13,0.12,1.69,0.12 c4.15,0,7.78-2.26,9.72-5.62c0.2-0.35-0.07-0.76-0.44-0.76c-0.05,0-0.1,0.01-0.15,0.02c-1.03,0.31-2.12,0.48-3.25,0.48 c-0.22,0-0.44-0.01-0.67-0.02C13.23,15.38,8.62,10.77,8.29,5.17C8.21,3.81,8.38,2.49,8.75,1.26C8.86,0.91,8.59,0.6,8.27,0.6 L8.27,0.6z" />
+</vector>
+
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index 14a5310a4ff2..3683bfd02e87 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -213,6 +213,65 @@
</LinearLayout>
</LinearLayout>
+ <!-- Layout Option 3: File preview, icon, filename, copy-->
+ <LinearLayout
+ android:id="@+id/content_preview_file_area"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/chooser_view_spacing"
+ android:visibility="gone"
+ android:background="?attr/colorBackgroundFloating">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:paddingLeft="@dimen/chooser_edge_margin_normal"
+ android:paddingRight="@dimen/chooser_edge_margin_normal"
+ android:layout_marginBottom="@dimen/chooser_view_spacing"
+ android:id="@+id/content_preview_file_layout">
+
+ <view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
+ android:id="@+id/content_preview_file_thumbnail"
+ android:layout_width="75dp"
+ android:layout_height="75dp"
+ android:layout_marginRight="16dp"
+ android:adjustViewBounds="true"
+ android:layout_gravity="center_vertical"
+ android:gravity="center"
+ android:scaleType="centerCrop"
+ android:visibility="gone"/>
+ <ImageView
+ android:id="@+id/content_preview_file_icon"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_marginRight="16dp"
+ android:adjustViewBounds="true"
+ android:layout_gravity="center_vertical"
+ android:gravity="center"
+ android:scaleType="fitCenter"
+ android:visibility="gone"/>
+ <TextView
+ android:id="@+id/content_preview_filename"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:ellipsize="middle"
+ android:gravity="start|top"
+ android:paddingRight="24dp"
+ android:singleLine="true"/>
+ <Button
+ android:id="@+id/file_copy_button"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:gravity="center"
+ android:layout_gravity="center_vertical"
+ android:background="@drawable/ic_content_copy_gm2"/>
+ </LinearLayout>
+ </LinearLayout>
+
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index 64d91ad867f9..13fef67c5e2f 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -66,7 +66,7 @@
android:id="@+id/media_actions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="bottom|end"
+ android:layout_gravity="top|end"
android:layout_marginStart="10dp"
android:layoutDirection="ltr"
android:orientation="horizontal"
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 53cae638db80..1053184bc2fc 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -118,7 +118,7 @@
<attr name="manageSpaceActivity" format="string" />
<!-- Option to let applications specify that user data can/cannot be
- cleared. This flag is turned on by default.
+ cleared by the user in Settings. This flag is turned on by default.
<em>This attribute is usable only by applications
included in the system image. Third-party apps cannot use it.</em> -->
<attr name="allowClearUserData" format="boolean" />
@@ -1661,7 +1661,12 @@
<!-- If {@code true} the user is prompted to keep the app's data on uninstall -->
<attr name="hasFragileUserData" />
- <attr name="zygotePreloadName" />
+ <attr name="zygotePreloadName" />
+
+ <!-- If {@code true} the system will clear app's data if a restore operation fails.
+ This flag is turned on by default. <em>This attribute is usable only by system apps.
+ </em> -->
+ <attr name="allowClearUserDataOnFailedRestore"/>
</declare-styleable>
<!-- The <code>permission</code> tag declares a security permission that can be
used to control access from other packages to specific components or
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a501ae2661c6..dae2692c7722 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1951,6 +1951,10 @@
<string name="config_defaultDialer" translatable="false">com.android.phone</string>
<!-- The name of the package that will hold the SMS role by default. -->
<string name="config_defaultSms" translatable="false">@string/default_sms_application</string>
+ <!-- The name of the package that will hold the music role by default. -->
+ <string name="config_defaultMusic" translatable="false">com.android.music</string>
+ <!-- The name of the package that will hold the gallery role by default. -->
+ <string name="config_defaultGallery" translatable="false">com.android.gallery3d</string>
<!-- Enable/disable default bluetooth profiles:
HSP_AG, ObexObjectPush, Audio, NAP -->
@@ -3248,7 +3252,7 @@
skinny aspect ratio that is not expected to be widely used. -->
<item name="config_pictureInPictureMinAspectRatio" format="float" type="dimen">0.41841004184</item>
- <!-- The minimum aspect ratio (width/height) that is supported for picture-in-picture. Any
+ <!-- The maximum aspect ratio (width/height) that is supported for picture-in-picture. Any
ratio larger than this is considered to wide and short to be usable. Currently 2.39:1. -->
<item name="config_pictureInPictureMaxAspectRatio" format="float" type="dimen">2.39</item>
@@ -3269,6 +3273,11 @@
-->
<integer name="config_dockedStackDividerSnapMode">0</integer>
+ <!-- The maximum aspect ratio (longerSide/shorterSide) that is treated as close-to-square. If
+ config_forceDefaultOrientation is set to true, the rotation on a close-to-square display
+ will be fixed. -->
+ <item name="config_closeToSquareDisplayMaxAspectRatio" format="float" type="dimen">1.333</item>
+
<!-- List of comma separated package names for which we the system will not show crash, ANR,
etc. dialogs. -->
<string translatable="false" name="config_appsNotReportingCrashes"></string>
@@ -3421,8 +3430,14 @@
-->
<string-array translatable="false" name="config_convert_to_emergency_number_map" />
- <!-- An array of packages for which notifications cannot be blocked. -->
- <string-array translatable="false" name="config_nonBlockableNotificationPackages" />
+ <!-- An array of packages for which notifications cannot be blocked.
+ Should only be used for core device functionality that must not be
+ rendered inoperative for safety reasons, like the phone dialer and
+ SMS handler. -->
+ <string-array translatable="false" name="config_nonBlockableNotificationPackages">
+ <item>com.android.dialer</item>
+ <item>com.android.messaging</item>
+ </string-array>
<!-- An array of packages which can listen for notifications on low ram devices. -->
<string-array translatable="false" name="config_allowedManagedServicesOnLowRamDevices" />
@@ -3893,4 +3908,22 @@
The ambient color temperature (in cct) to which we fall back when the ambient brightness
drops beneath a certain threshold. -->
<item name="config_displayWhiteBalanceLowLightAmbientColorTemperature" format="float" type="dimen">6500.0</item>
+
+ <!-- See DisplayWhiteBalanceController.
+ A float array containing a list of ambient color temperatures, in Kelvin. This array,
+ together with config_displayWhiteBalanceDisplayTemperatureValues, is used to generate a
+ lookup table used in DisplayWhiteBalanceController. This lookup table is used to map
+ ambient color temperature readings to a target color temperature for the display.
+ This table is optional. If used, this array must,
+ 1) Contain at least two entries
+ 2) Be the same length as config_displayWhiteBalanceDisplayTemperatureValues. -->
+ <array name="config_displayWhiteBalanceAmbientTemperatureValues">
+ </array>
+
+ <!-- See DisplayWhiteBalanceController.
+ An array containing a list of display color temperatures, in Kelvin. See
+ config_displayWhiteBalanceAmbientTemperatureValues for additional details.
+ The same restrictions apply to this array. -->
+ <array name="config_displayWhiteBalanceDisplayTemperatureValues">
+ </array>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index d5cefc4e4818..5e65605a4c65 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2939,6 +2939,8 @@
<public name="zygotePreloadName" />
<public name="useEmbeddedDex" />
<public name="forceUriPermissions" />
+ <!-- @hide @SystemApi -->
+ <public name="allowClearUserDataOnFailedRestore"/>
</public-group>
<public-group type="drawable" first-id="0x010800b4">
@@ -2979,6 +2981,10 @@
<public name="config_defaultDialer" />
<!-- @hide @SystemApi -->
<public name="config_defaultSms" />
+ <!-- @hide @SystemApi -->
+ <public name="config_defaultMusic" />
+ <!-- @hide @SystemApi -->
+ <public name="config_defaultGallery" />
</public-group>
<public-group type="bool" first-id="0x01110000">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 75a91ebdd913..0cdf38849d8b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1406,9 +1406,9 @@
re-enables the keylock when the call is finished.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=NONE] -->
- <string name="permlab_getAndRequestScreenLockComplexity">get and request screen lock complexity</string>
+ <string name="permlab_requestScreenLockComplexity">request screen lock complexity</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=NONE] -->
- <string name="permdesc_getAndRequestScreenLockComplexity">Allows the app to learn the screen
+ <string name="permdesc_requestScreenLockComplexity">Allows the app to learn the screen
lock complexity level (high, medium, low or none), which indicates the possible range of
length and type of the screen lock. The app can also suggest to users that they update the
screen lock to a certain level but users can freely ignore and navigate away. Note that the
@@ -1471,6 +1471,8 @@
<string name="biometric_not_recognized">Not recognized</string>
<!-- Message shown when biometric authentication has been canceled [CHAR LIMIT=50] -->
<string name="biometric_error_canceled">Authentication canceled</string>
+ <!-- Message returned to applications if BiometricPrompt setAllowDeviceCredentials is enabled but no pin, pattern, or password is set. [CHAR LIMIT=NONE] -->
+ <string name="biometric_error_device_not_secured">No pin, pattern, or password set</string>
<!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
<string name="fingerprint_acquired_partial">Partial fingerprint detected. Please try again.</string>
@@ -5282,4 +5284,9 @@
<!-- Strings for car -->
<!-- String displayed when loading a user in the car [CHAR LIMIT=30] -->
<string name="car_loading_profile">Loading</string>
+
+ <plurals name="file_count">
+ <item quantity="one"><xliff:g id="file_name">%s</xliff:g> + <xliff:g id="count">%d</xliff:g> file</item>
+ <item quantity="other"><xliff:g id="file_name">%s</xliff:g> + <xliff:g id="count">%d</xliff:g> files</item>
+ </plurals>
</resources>
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 0dc54e091f9d..93068ea975bd 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -41,9 +41,7 @@ easier.
<item name="textAppearance">?attr/textAppearanceButton</item>
<item name="textColor">@color/btn_colored_text_material</item>
</style>
- <style name="Widget.DeviceDefault.TextView" parent="Widget.Material.TextView">
- <item name="fontFamily">@string/config_bodyFontFamily</item>
- </style>
+ <style name="Widget.DeviceDefault.TextView" parent="Widget.Material.TextView" />
<style name="Widget.DeviceDefault.CheckedTextView" parent="Widget.Material.CheckedTextView"/>
<style name="Widget.DeviceDefault.AutoCompleteTextView" parent="Widget.Material.AutoCompleteTextView"/>
<style name="Widget.DeviceDefault.CompoundButton.CheckBox" parent="Widget.Material.CompoundButton.CheckBox"/>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 32d63e43ccb1..01abffeed384 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -50,6 +50,11 @@
<java-symbol type="id" name="characterPicker" />
<java-symbol type="id" name="clearDefaultHint" />
<java-symbol type="id" name="contentPanel" />
+ <java-symbol type="id" name="content_preview_file_area" />
+ <java-symbol type="id" name="content_preview_file_icon" />
+ <java-symbol type="id" name="content_preview_file_layout" />
+ <java-symbol type="id" name="content_preview_file_thumbnail" />
+ <java-symbol type="id" name="content_preview_filename" />
<java-symbol type="id" name="content_preview_image_area" />
<java-symbol type="id" name="content_preview_image_1_large" />
<java-symbol type="id" name="content_preview_image_2_large" />
@@ -62,6 +67,7 @@
<java-symbol type="id" name="content_preview_title" />
<java-symbol type="id" name="content_preview_title_layout" />
<java-symbol type="id" name="copy_button" />
+ <java-symbol type="id" name="file_copy_button" />
<java-symbol type="id" name="current_scene" />
<java-symbol type="id" name="scene_layoutid_cache" />
<java-symbol type="id" name="customPanel" />
@@ -397,6 +403,7 @@
<java-symbol type="integer" name="config_defaultPictureInPictureGravity" />
<java-symbol type="dimen" name="config_pictureInPictureMinAspectRatio" />
<java-symbol type="dimen" name="config_pictureInPictureMaxAspectRatio" />
+ <java-symbol type="dimen" name="config_closeToSquareDisplayMaxAspectRatio" />
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_threshold" />
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_factor" />
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_penalty_threshold" />
@@ -1266,6 +1273,7 @@
<java-symbol type="string" name="tooltip_popup_title" />
<java-symbol type="plurals" name="bugreport_countdown" />
+ <java-symbol type="plurals" name="file_count" />
<java-symbol type="plurals" name="last_num_days" />
<java-symbol type="plurals" name="matches_found" />
<java-symbol type="plurals" name="restr_pin_countdown" />
@@ -1307,6 +1315,7 @@
<java-symbol type="drawable" name="default_wallpaper" />
<java-symbol type="drawable" name="default_lock_wallpaper" />
<java-symbol type="drawable" name="indicator_input_error" />
+ <java-symbol type="drawable" name="ic_file_copy" />
<java-symbol type="drawable" name="popup_bottom_dark" />
<java-symbol type="drawable" name="popup_bottom_bright" />
<java-symbol type="drawable" name="popup_bottom_medium" />
@@ -2473,6 +2482,7 @@
<java-symbol type="string" name="biometric_error_user_canceled" />
<java-symbol type="string" name="biometric_not_recognized" />
<java-symbol type="string" name="biometric_error_canceled" />
+ <java-symbol type="string" name="biometric_error_device_not_secured" />
<!-- Fingerprint messages -->
<java-symbol type="string" name="fingerprint_error_unable_to_process" />
@@ -3642,4 +3652,7 @@
<java-symbol type="array" name="config_displayWhiteBalanceDecreaseThresholds" />
<java-symbol type="dimen" name="config_displayWhiteBalanceLowLightAmbientBrightnessThreshold" />
<java-symbol type="dimen" name="config_displayWhiteBalanceLowLightAmbientColorTemperature" />
+ <java-symbol type="array" name="config_displayWhiteBalanceAmbientTemperatureValues" />
+ <java-symbol type="array" name="config_displayWhiteBalanceDisplayTemperatureValues" />
+ <java-symbol type="drawable" name="ic_action_open" />
</resources>
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
index 300394d426e4..aa0e0cdae265 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
@@ -162,14 +162,13 @@ public class PackageParserTest {
}
private void verifyComputeTargetSdkVersion(int targetSdkVersion, String targetSdkCodename,
- boolean isPlatformReleased, int expectedTargetSdk, boolean forceCurrentDev) {
+ boolean isPlatformReleased, int expectedTargetSdk) {
final String[] outError = new String[1];
final int result = PackageParser.computeTargetSdkVersion(
targetSdkVersion,
targetSdkCodename,
isPlatformReleased ? CODENAMES_RELEASED : CODENAMES_PRE_RELEASE,
- outError,
- forceCurrentDev);
+ outError);
assertEquals(result, expectedTargetSdk);
@@ -185,28 +184,23 @@ public class PackageParserTest {
// Do allow older release targetSdkVersion on pre-release platform.
// APP: Released API 10
// DEV: Pre-release API 20
- verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, false, OLDER_VERSION,
- false /* forceCurrentDev */);
+ verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, false, OLDER_VERSION);
// Do allow same release targetSdkVersion on pre-release platform.
// APP: Released API 20
// DEV: Pre-release API 20
- verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, false, PLATFORM_VERSION,
- false /* forceCurrentDev */);
+ verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, false, PLATFORM_VERSION);
// Do allow newer release targetSdkVersion on pre-release platform.
// APP: Released API 30
// DEV: Pre-release API 20
- verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, false, NEWER_VERSION,
- false /* forceCurrentDev */);
+ verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, false, NEWER_VERSION);
// Don't allow older pre-release targetSdkVersion on pre-release platform.
// APP: Pre-release API 10
// DEV: Pre-release API 20
- verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, -1,
- false /* forceCurrentDev */);
- verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, false, -1,
- false /* forceCurrentDev */);
+ verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, -1);
+ verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, false, -1);
// Do allow same pre-release targetSdkVersion on pre-release platform,
@@ -214,27 +208,16 @@ public class PackageParserTest {
// APP: Pre-release API 20
// DEV: Pre-release API 20
verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, false,
- Build.VERSION_CODES.CUR_DEVELOPMENT, false /* forceCurrentDev */);
+ Build.VERSION_CODES.CUR_DEVELOPMENT);
verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, false,
- Build.VERSION_CODES.CUR_DEVELOPMENT, false /* forceCurrentDev */);
+ Build.VERSION_CODES.CUR_DEVELOPMENT);
// Don't allow newer pre-release targetSdkVersion on pre-release platform.
// APP: Pre-release API 30
// DEV: Pre-release API 20
- verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, -1,
- false /* forceCurrentDev */);
- verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false, -1,
- false /* forceCurrentDev */);
-
-
- // Force newer pre-release targetSdkVersion to current pre-release platform.
- // APP: Pre-release API 30
- // DEV: Pre-release API 20
- verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false,
- Build.VERSION_CODES.CUR_DEVELOPMENT, true /* forceCurrentDev */);
- verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false,
- Build.VERSION_CODES.CUR_DEVELOPMENT, true /* forceCurrentDev */);
+ verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, -1);
+ verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false, -1);
}
@Test
@@ -242,45 +225,36 @@ public class PackageParserTest {
// Do allow older release targetSdkVersion on released platform.
// APP: Released API 10
// DEV: Released API 20
- verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, true, OLDER_VERSION,
- false /* forceCurrentDev */);
+ verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, true, OLDER_VERSION);
// Do allow same release targetSdkVersion on released platform.
// APP: Released API 20
// DEV: Released API 20
- verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, true, PLATFORM_VERSION,
- false /* forceCurrentDev */);
+ verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, true, PLATFORM_VERSION);
// Do allow newer release targetSdkVersion on released platform.
// APP: Released API 30
// DEV: Released API 20
- verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, true, NEWER_VERSION,
- false /* forceCurrentDev */);
+ verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, true, NEWER_VERSION);
// Don't allow older pre-release targetSdkVersion on released platform.
// APP: Pre-release API 10
// DEV: Released API 20
- verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, -1,
- false /* forceCurrentDev */);
- verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, true, -1,
- false /* forceCurrentDev */);
+ verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, -1);
+ verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, true, -1);
// Don't allow same pre-release targetSdkVersion on released platform.
// APP: Pre-release API 20
// DEV: Released API 20
- verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, -1,
- false /* forceCurrentDev */);
- verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true, -1,
- false /* forceCurrentDev */);
+ verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, -1);
+ verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true, -1);
// Don't allow newer pre-release targetSdkVersion on released platform.
// APP: Pre-release API 30
// DEV: Released API 20
- verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1,
- false /* forceCurrentDev */);
- verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true, -1,
- false /* forceCurrentDev */);
+ verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1);
+ verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true, -1);
}
/**
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index ec57f793f15f..c57b609023ca 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -128,7 +128,6 @@ public class SettingsBackupTest {
Settings.Global.AUTOFILL_LOGGING_LEVEL,
Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE,
Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS,
- Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS,
Settings.Global.AUTOMATIC_POWER_SAVER_MODE,
Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED,
Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY,
@@ -492,8 +491,10 @@ public class SettingsBackupTest {
Settings.Global.GAME_DRIVER_ALL_APPS,
Settings.Global.GAME_DRIVER_OPT_IN_APPS,
Settings.Global.GAME_DRIVER_OPT_OUT_APPS,
+ Settings.Global.GAME_DRIVER_BLACKLISTS,
Settings.Global.GAME_DRIVER_BLACKLIST,
Settings.Global.GAME_DRIVER_WHITELIST,
+ Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX,
Settings.Global.GPU_DEBUG_LAYER_APP,
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT,
@@ -620,6 +621,7 @@ public class SettingsBackupTest {
Settings.Secure.DISABLED_PRINT_SERVICES,
Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS,
Settings.Secure.DISPLAY_DENSITY_FORCED,
+ Settings.Secure.DOCKED_CLOCK_FACE,
Settings.Secure.DOZE_PULSE_ON_LONG_PRESS,
Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION,
Settings.Secure.ENABLED_INPUT_METHODS, // Intentionally removed in P
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
index f325d8943ea3..a97c3fa362eb 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
@@ -15,6 +15,7 @@
*/
package android.view.contentcapture;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_CONTEXT_UPDATED;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_FINISHED;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_STARTED;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_DISAPPEARED;
@@ -174,7 +175,8 @@ public class ContentCaptureEventTest {
assertThat(event.getIds()).isNull();
assertThat(event.getText()).isNull();
assertThat(event.getViewNode()).isNull();
- final ContentCaptureContext clientContext = event.getClientContext();
+ final ContentCaptureContext clientContext = event.getContentCaptureContext();
+ assertThat(clientContext).isNotNull();
assertThat(clientContext.getAction()).isEqualTo("WHATEVER");
}
@@ -205,9 +207,44 @@ public class ContentCaptureEventTest {
assertThat(event.getIds()).isNull();
assertThat(event.getText()).isNull();
assertThat(event.getViewNode()).isNull();
- assertThat(event.getClientContext()).isNull();
+ assertThat(event.getContentCaptureContext()).isNull();
}
+
+ @Test
+ public void testContextUpdated_directly() {
+ final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_CONTEXT_UPDATED)
+ .setClientContext(mClientContext);
+ assertThat(event).isNotNull();
+ assertContextUpdatedEvent(event);
+ }
+
+ @Test
+ public void testContextUpdated_throughParcel() {
+ final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_CONTEXT_UPDATED)
+ .setClientContext(mClientContext);
+ assertThat(event).isNotNull();
+ final ContentCaptureEvent clone = cloneThroughParcel(event);
+ assertContextUpdatedEvent(clone);
+ }
+
+ private void assertContextUpdatedEvent(ContentCaptureEvent event) {
+ assertThat(event.getType()).isEqualTo(TYPE_CONTEXT_UPDATED);
+ assertThat(event.getEventTime()).isAtLeast(MY_EPOCH);
+ assertThat(event.getSessionId()).isEqualTo("42");
+ assertThat(event.getParentSessionId()).isNull();
+ assertThat(event.getId()).isNull();
+ assertThat(event.getIds()).isNull();
+ assertThat(event.getText()).isNull();
+ assertThat(event.getViewNode()).isNull();
+ final ContentCaptureContext clientContext = event.getContentCaptureContext();
+ assertThat(clientContext).isNotNull();
+ assertThat(clientContext.getAction()).isEqualTo("WHATEVER");
+ }
+
+ // TODO(b/123036895): add test for all events type (right now we're just testing the 3 types
+ // that use logic to write to parcel
+
private ContentCaptureEvent cloneThroughParcel(ContentCaptureEvent event) {
Parcel parcel = Parcel.obtain();
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
index 34fdebfdf348..b6717e16256f 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
@@ -160,5 +160,10 @@ public class ContentCaptureSessionTest {
public void internalNotifyViewHierarchyEvent(boolean started) {
throw new UnsupportedOperationException("should not have been called");
}
+
+ @Override
+ public void updateContentCaptureContext(ContentCaptureContext context) {
+ throw new UnsupportedOperationException("should not have been called");
+ }
}
}
diff --git a/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java b/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
index 213cd405e903..93315f11d242 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
@@ -20,11 +20,12 @@ import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.graphics.Matrix;
-import android.support.test.InstrumentationRegistry;
import android.view.View;
import android.view.ViewStructure.HtmlInfo;
import android.view.contentcapture.ViewNode.ViewStructureImpl;
+import androidx.test.InstrumentationRegistry;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
index 32bafec4081a..fe2a6608c781 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
@@ -195,11 +195,13 @@ public class TextClassificationConstantsTest {
assertWithMessage("in_app_conversation_action_types_default")
.that(constants.getInAppConversationActionTypes())
.containsExactly("text_reply", "create_reminder", "call_phone", "open_url",
- "send_email", "send_sms", "track_flight", "view_calendar", "view_map");
+ "send_email", "send_sms", "track_flight", "view_calendar", "view_map",
+ "add_contact");
assertWithMessage("notification_conversation_action_types_default")
.that(constants.getNotificationConversationActionTypes())
.containsExactly("text_reply", "create_reminder", "call_phone", "open_url",
- "send_email", "send_sms", "track_flight", "view_calendar", "view_map");
+ "send_email", "send_sms", "track_flight", "view_calendar", "view_map",
+ "add_contact");
assertWithMessage("lang_id_threshold_override")
.that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(-1f);
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index bdd03707c1f1..d2d03e565522 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -382,7 +382,6 @@ public class TextClassifierTest {
assertThat(textLanguage, isTextLanguage("ja"));
}
- /* DISABLED: b/122467291
@Test
public void testSuggestConversationActions_textReplyOnly_maxThree() {
if (isTextClassifierDisabled()) return;
@@ -410,7 +409,7 @@ public class TextClassifierTest {
assertThat(conversationAction,
isConversationAction(ConversationAction.TYPE_TEXT_REPLY));
}
- }*/
+ }
@Test
public void testSuggestConversationActions_textReplyOnly_noMax() {
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 3d59835a6719..7f104b1b0a14 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -409,8 +409,7 @@ public class ChooserActivityTest {
@Test
public void copyTextToClipboard() throws Exception {
Intent sendIntent = createSendTextIntent();
- List<ResolvedComponentInfo> resolvedComponentInfos =
- createResolvedComponentsForTestWithOtherProfile(1);
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
when(ChooserWrapperActivity.sOverrides.resolverListController.getResolversForIntent(
Mockito.anyBoolean(),
@@ -421,6 +420,7 @@ public class ChooserActivityTest {
.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
+ onView(withId(R.id.copy_button)).check(matches(isDisplayed()));
onView(withId(R.id.copy_button)).perform(click());
ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(
Context.CLIPBOARD_SERVICE);
@@ -439,8 +439,9 @@ public class ChooserActivityTest {
ArrayList<Uri> uris = new ArrayList<>();
uris.add(uri);
- Intent sendIntent = createSendImageIntentWithPreview(uris);
+ Intent sendIntent = createSendUriIntentWithPreview(uris);
sOverrides.previewThumbnail = createBitmap();
+ sOverrides.isImageType = true;
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -464,8 +465,9 @@ public class ChooserActivityTest {
uris.add(uri);
uris.add(uri);
- Intent sendIntent = createSendImageIntentWithPreview(uris);
+ Intent sendIntent = createSendUriIntentWithPreview(uris);
sOverrides.previewThumbnail = createBitmap();
+ sOverrides.isImageType = true;
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -492,8 +494,9 @@ public class ChooserActivityTest {
uris.add(uri);
uris.add(uri);
- Intent sendIntent = createSendImageIntentWithPreview(uris);
+ Intent sendIntent = createSendUriIntentWithPreview(uris);
sOverrides.previewThumbnail = createBitmap();
+ sOverrides.isImageType = true;
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -538,12 +541,11 @@ public class ChooserActivityTest {
ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "empty preview logger test"));
waitForIdle();
- verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture());
+
+ verify(mockLogger, Mockito.times(1)).write(logMakerCaptor.capture());
// First invocation is from onCreate
- assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
- is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
- assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(),
- is(CONTENT_PREVIEW_TEXT));
+ assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
+ is(MetricsProto.MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
}
@Test
@@ -552,9 +554,17 @@ public class ChooserActivityTest {
MetricsLogger mockLogger = sOverrides.metricsLogger;
ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+
+ when(ChooserWrapperActivity.sOverrides.resolverListController.getResolversForIntent(
+ Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture());
+ verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
// First invocation is from onCreate
assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
@@ -570,8 +580,9 @@ public class ChooserActivityTest {
ArrayList<Uri> uris = new ArrayList<>();
uris.add(uri);
- Intent sendIntent = createSendImageIntentWithPreview(uris);
+ Intent sendIntent = createSendUriIntentWithPreview(uris);
sOverrides.previewThumbnail = createBitmap();
+ sOverrides.isImageType = true;
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -595,6 +606,51 @@ public class ChooserActivityTest {
is(CONTENT_PREVIEW_IMAGE));
}
+ @Test
+ public void oneVisibleFilePreview() throws InterruptedException {
+ Uri uri = Uri.parse("content://com.android.frameworks.coretests/app.pdf");
+
+ ArrayList<Uri> uris = new ArrayList<>();
+ uris.add(uri);
+
+ Intent sendIntent = createSendUriIntentWithPreview(uris);
+
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+ waitForIdle();
+ onView(withId(R.id.content_preview_filename)).check(matches(isDisplayed()));
+ onView(withId(R.id.content_preview_filename)).check(matches(withText("app.pdf")));
+ onView(withId(R.id.content_preview_file_icon)).check(matches(isDisplayed()));
+ }
+
+
+ @Test
+ public void moreThanOneVisibleFilePreview() throws InterruptedException {
+ Uri uri = Uri.parse("content://com.android.frameworks.coretests/app.pdf");
+
+ ArrayList<Uri> uris = new ArrayList<>();
+ uris.add(uri);
+ uris.add(uri);
+ uris.add(uri);
+
+ Intent sendIntent = createSendUriIntentWithPreview(uris);
+
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+ waitForIdle();
+ onView(withId(R.id.content_preview_filename)).check(matches(isDisplayed()));
+ onView(withId(R.id.content_preview_filename)).check(matches(withText("app.pdf + 2 files")));
+ onView(withId(R.id.content_preview_file_icon)).check(matches(isDisplayed()));
+ }
+
private Intent createSendTextIntent() {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
@@ -615,7 +671,7 @@ public class ChooserActivityTest {
return sendIntent;
}
- private Intent createSendImageIntentWithPreview(ArrayList<Uri> uris) {
+ private Intent createSendUriIntentWithPreview(ArrayList<Uri> uris) {
Intent sendIntent = new Intent();
if (uris.size() > 1) {
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index f60467bd3df2..096b78b95fbd 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -89,11 +89,7 @@ public class ChooserWrapperActivity extends ChooserActivity {
@Override
protected boolean isImageType(String mimeType) {
- if (sOverrides.previewThumbnail != null) {
- return true;
- }
-
- return super.isImageType(mimeType);
+ return sOverrides.isImageType;
}
@Override
@@ -112,6 +108,7 @@ public class ChooserWrapperActivity extends ChooserActivity {
public Function<TargetInfo, Boolean> onSafelyStartCallback;
public ResolverListController resolverListController;
public Boolean isVoiceInteraction;
+ public boolean isImageType;
public Bitmap previewThumbnail;
public MetricsLogger metricsLogger;
@@ -120,6 +117,7 @@ public class ChooserWrapperActivity extends ChooserActivity {
isVoiceInteraction = null;
createPackageManager = null;
previewThumbnail = null;
+ isImageType = false;
resolverListController = mock(ResolverListController.class);
metricsLogger = mock(MetricsLogger.class);
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
index 1d35143e3fab..e375af3f7b0e 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -658,6 +658,67 @@ public class BinderCallsStatsTest {
assertTrue(debugEntry3.latencyMicros >= 0);
}
+ @Test
+ public void testTrackScreenInteractiveDisabled() {
+ TestBinderCallsStats bcs = new TestBinderCallsStats();
+ bcs.setTrackScreenInteractive(false);
+ Binder binder = new Binder();
+
+ mDeviceState.setScreenInteractive(false);
+ CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID);
+ bcs.time += 10;
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
+
+ mDeviceState.setScreenInteractive(true);
+ callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID);
+ bcs.time += 1000; // shoud be ignored.
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
+
+ SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries();
+ assertEquals(1, uidEntries.size());
+ BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID);
+ Assert.assertNotNull(uidEntry);
+ assertEquals(2, uidEntry.callCount);
+
+ List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList());
+ assertEquals(1, callStatsList.size());
+ BinderCallsStats.CallStat callStats = callStatsList.get(0);
+ assertEquals(false, callStats.screenInteractive);
+ assertEquals(2, callStats.callCount);
+ assertEquals(2, callStats.recordedCallCount);
+ }
+
+ @Test
+ public void testTrackCallingUidDisabled() {
+ TestBinderCallsStats bcs = new TestBinderCallsStats();
+ bcs.setTrackDirectCallerUid(false);
+ Binder binder = new Binder();
+
+ bcs.setCallingUid(1);
+ CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID);
+ bcs.time += 10;
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
+
+ bcs.setCallingUid(2);
+ callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID);
+ bcs.time += 1000; // shoud be ignored.
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
+
+ SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries();
+ assertEquals(1, uidEntries.size());
+ BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID);
+ Assert.assertNotNull(uidEntry);
+ assertEquals(2, uidEntry.callCount);
+
+ List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList());
+ assertEquals(1, callStatsList.size());
+ BinderCallsStats.CallStat callStats = callStatsList.get(0);
+ assertEquals(-1, callStats.callingUid);
+ assertEquals(2, callStats.callCount);
+ assertEquals(2, callStats.recordedCallCount);
+ }
+
+
class TestBinderCallsStats extends BinderCallsStats {
public int callingUid = CALLING_UID;
public long time = 1234;
@@ -682,6 +743,8 @@ public class BinderCallsStatsTest {
});
setSamplingInterval(1);
setAddDebugEntries(false);
+ setTrackScreenInteractive(true);
+ setTrackDirectCallerUid(true);
if (deviceState != null) {
setDeviceState(deviceState.getReadonlyClient());
}
@@ -701,6 +764,10 @@ public class BinderCallsStatsTest {
protected int getCallingUid() {
return callingUid;
}
+
+ protected void setCallingUid(int uid) {
+ callingUid = uid;
+ }
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
index 64b7c2cce946..1c84829c5491 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
@@ -124,7 +124,7 @@ public class KernelCpuThreadReaderEndToEndTest {
// Get thread data from KernelCpuThreadReader
final KernelCpuThreadReader kernelCpuThreadReader =
- KernelCpuThreadReader.create(8, uid -> uid == Process.myUid());
+ KernelCpuThreadReader.create(8, uid -> uid == Process.myUid(), 0);
assertNotNull(kernelCpuThreadReader);
final ProcessCpuUsage currentProcessCpuUsage =
kernelCpuThreadReader.getCurrentProcessCpuUsage();
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
index b9744f599a9a..442ece5a884d 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
@@ -103,6 +103,7 @@ public class KernelCpuThreadReaderTest {
final KernelCpuThreadReader kernelCpuThreadReader = new KernelCpuThreadReader(
8,
uid -> 1000 <= uid && uid < 2000,
+ 0,
mProcDirectory.toPath(),
mProcDirectory.toPath().resolve("self/task/" + THREAD_IDS[0] + "/time_in_state"),
processUtils);
@@ -144,6 +145,7 @@ public class KernelCpuThreadReaderTest {
final KernelCpuThreadReader kernelCpuThreadReader = new KernelCpuThreadReader(
8,
uidPredicate,
+ 0,
mProcDirectory.toPath(),
mProcDirectory.toPath().resolve(uids[0] + "/task/" + uids[0] + "/time_in_state"),
processUtils);
@@ -162,6 +164,60 @@ public class KernelCpuThreadReaderTest {
}
}
+ @Test
+ public void testReader_filtersLowUsage() throws IOException {
+ int[] uids = new int[]{0, 1, 2, 3, 4};
+ int[] cpuUsage = new int[]{10, 0, 2, 100, 3};
+ int[] expectedUids = new int[]{0, 3, 4};
+ Predicate<Integer> uidPredicate = uid -> true;
+ KernelCpuThreadReader.Injector processUtils =
+ new KernelCpuThreadReader.Injector() {
+ @Override
+ public int myPid() {
+ return 0;
+ }
+
+ @Override
+ public int myUid() {
+ return 0;
+ }
+
+ @Override
+ public int getUidForPid(int pid) {
+ return pid;
+ }
+ };
+
+ for (int i = 0; i < uids.length; i++) {
+ int uid = uids[i];
+ setupDirectory(
+ mProcDirectory.toPath().resolve(String.valueOf(uid)),
+ new int[]{uid * 10},
+ "process" + uid,
+ new String[]{"thread" + uid},
+ new int[]{1000},
+ new int[][]{{cpuUsage[i]}});
+ }
+ final KernelCpuThreadReader kernelCpuThreadReader = new KernelCpuThreadReader(
+ 8,
+ uidPredicate,
+ 30,
+ mProcDirectory.toPath(),
+ mProcDirectory.toPath().resolve(uids[0] + "/task/" + uids[0] + "/time_in_state"),
+ processUtils);
+ ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsageByUids =
+ kernelCpuThreadReader.getProcessCpuUsageByUids();
+ processCpuUsageByUids.sort(Comparator.comparing(usage -> usage.uid));
+
+ assertEquals(expectedUids.length, processCpuUsageByUids.size());
+ for (int i = 0; i < expectedUids.length; i++) {
+ KernelCpuThreadReader.ProcessCpuUsage processCpuUsage =
+ processCpuUsageByUids.get(i);
+ assertEquals(expectedUids[i], processCpuUsage.uid);
+ }
+
+ }
+
private void setupDirectory(Path processPath, int[] threadIds, String processName,
String[] threadNames, int[] cpuFrequencies, int[][] cpuTimes) throws IOException {
// Make /proc/$PID
@@ -328,7 +384,6 @@ public class KernelCpuThreadReaderTest {
new long[]{1, 1, 1, 1, 1, 1, 1, 1}));
}
-
@Test
public void testGetBigFrequenciesStartIndex_simple() {
assertEquals(
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index 79b847754311..3edf5f87258b 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -476,6 +476,33 @@ public final class LooperStatsTest {
assertThat(debugEntry3.totalLatencyMicros).isAtLeast(0L);
}
+ @Test
+ public void testScreenStateTrackingDisabled() {
+ TestableLooperStats looperStats = new TestableLooperStats(1, 100);
+ looperStats.setTrackScreenInteractive(false);
+
+ Message message = mHandlerFirst.obtainMessage(1000);
+ message.workSourceUid = 1000;
+ message.when = looperStats.getSystemUptimeMillis();
+
+ looperStats.tickUptime(30);
+ mDeviceState.setScreenInteractive(false);
+ Object token = looperStats.messageDispatchStarting();
+ looperStats.messageDispatched(token, message);
+
+ looperStats.tickUptime(30);
+ mDeviceState.setScreenInteractive(true);
+ token = looperStats.messageDispatchStarting();
+ looperStats.messageDispatched(token, message);
+
+ List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
+ assertThat(entries).hasSize(1);
+ LooperStats.ExportedEntry entry = entries.get(0);
+ assertThat(entry.isInteractive).isEqualTo(false);
+ assertThat(entry.messageCount).isEqualTo(2);
+ assertThat(entry.recordedMessageCount).isEqualTo(2);
+ }
+
private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) {
try {
r.run();
@@ -501,6 +528,7 @@ public final class LooperStatsTest {
super(samplingInterval, sizeCap);
mSamplingInterval = samplingInterval;
setAddDebugEntries(false);
+ setTrackScreenInteractive(true);
if (deviceState != null) {
setDeviceState(deviceState.getReadonlyClient());
}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 6770ae19ce3d..915cf954f665 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -209,21 +209,14 @@ applications that come with the platform
<privapp-permissions package="com.android.mainline.networkstack">
<permission name="android.permission.ACCESS_NETWORK_CONDITIONS"/>
- <permission name="android.permission.CHANGE_BACKGROUND_DATA_SETTING"/>
<permission name="android.permission.CONNECTIVITY_INTERNAL"/>
<permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
<permission name="android.permission.CONTROL_VPN"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.LOCAL_MAC_ADDRESS"/>
- <permission name="android.permission.MANAGE_IPSEC_TUNNELS"/>
- <permission name="android.permission.MANAGE_NETWORK_POLICY"/>
<permission name="android.permission.MANAGE_SUBSCRIPTION_PLANS"/>
<permission name="android.permission.MANAGE_USB"/>
- <permission name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"/>
- <permission name="android.permission.NETWORK_SETTINGS"/>
- <permission name="android.permission.NETWORK_STACK" />
- <permission name="android.permission.NET_TUNNELING"/>
<permission name="android.permission.PACKET_KEEPALIVE_OFFLOAD"/>
- <permission name="android.permission.PEERS_MAC_ADDRESS"/>
<permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
<permission name="android.permission.READ_PRECISE_PHONE_STATE"/>
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
@@ -261,6 +254,7 @@ applications that come with the platform
<permission name="android.permission.CHANGE_LOWPAN_STATE"/>
<permission name="android.permission.CHANGE_OVERLAY_PACKAGES"/>
<permission name="android.permission.CLEAR_APP_CACHE"/>
+ <permission name="android.permission.ACCESS_INSTANT_APPS" />
<permission name="android.permission.CONNECTIVITY_INTERNAL"/>
<permission name="android.permission.DELETE_CACHE_FILES"/>
<permission name="android.permission.DELETE_PACKAGES"/>
@@ -334,4 +328,9 @@ applications that come with the platform
<permission name="android.permission.CONTROL_VPN"/>
</privapp-permissions>
+ <privapp-permissions package="com.android.dynandroid">
+ <permission name="android.permission.REBOOT"/>
+ <permission name="android.permission.MANAGE_DYNAMIC_ANDROID"/>
+ </privapp-permissions>
+
</permissions>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 18f0cae4733c..bdb63643f615 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -891,8 +891,10 @@ public final class Bitmap implements Parcelable {
}
}
+ ColorSpace cs = source.getColorSpace();
+
if (m == null || m.isIdentity()) {
- bitmap = createBitmap(neww, newh, newConfig, source.hasAlpha());
+ bitmap = createBitmap(null, neww, newh, newConfig, source.hasAlpha(), cs);
paint = null; // not needed
} else {
final boolean transformed = !m.rectStaysRect();
@@ -906,9 +908,14 @@ public final class Bitmap implements Parcelable {
if (transformed) {
if (transformedConfig != Config.ARGB_8888 && transformedConfig != Config.RGBA_F16) {
transformedConfig = Config.ARGB_8888;
+ if (cs == null) {
+ cs = ColorSpace.get(ColorSpace.Named.SRGB);
+ }
}
}
- bitmap = createBitmap(neww, newh, transformedConfig, transformed || source.hasAlpha());
+
+ bitmap = createBitmap(null, neww, newh, transformedConfig,
+ transformed || source.hasAlpha(), cs);
paint = new Paint();
paint.setFilterBitmap(filter);
@@ -917,8 +924,6 @@ public final class Bitmap implements Parcelable {
}
}
- nativeCopyColorSpace(source.mNativePtr, bitmap.mNativePtr);
-
// The new bitmap was created from a known bitmap source so assume that
// they use the same density
bitmap.mDensity = source.mDensity;
@@ -1000,10 +1005,10 @@ public final class Bitmap implements Parcelable {
* @param hasAlpha If the bitmap is ARGB_8888 or RGBA_16F this flag can be used to
* mark the bitmap as opaque. Doing so will clear the bitmap in black
* instead of transparent.
- * @param colorSpace The color space of the bitmap. If the config is {@link Config#RGBA_F16},
- * {@link ColorSpace.Named#EXTENDED_SRGB scRGB} is assumed, and if the
- * config is not {@link Config#ARGB_8888}, {@link ColorSpace.Named#SRGB sRGB}
- * is assumed.
+ * @param colorSpace The color space of the bitmap. If the config is {@link Config#RGBA_F16}
+ * and {@link ColorSpace.Named#SRGB sRGB} or
+ * {@link ColorSpace.Named#LINEAR_SRGB Linear sRGB} is provided then the
+ * corresponding extended range variant is assumed.
*
* @throws IllegalArgumentException if the width or height are <= 0, if
* Config is Config.HARDWARE (because hardware bitmaps are always
@@ -1055,10 +1060,10 @@ public final class Bitmap implements Parcelable {
* @param hasAlpha If the bitmap is ARGB_8888 or RGBA_16F this flag can be used to
* mark the bitmap as opaque. Doing so will clear the bitmap in black
* instead of transparent.
- * @param colorSpace The color space of the bitmap. If the config is {@link Config#RGBA_F16},
- * {@link ColorSpace.Named#EXTENDED_SRGB scRGB} is assumed, and if the
- * config is not {@link Config#ARGB_8888}, {@link ColorSpace.Named#SRGB sRGB}
- * is assumed.
+ * @param colorSpace The color space of the bitmap. If the config is {@link Config#RGBA_F16}
+ * and {@link ColorSpace.Named#SRGB sRGB} or
+ * {@link ColorSpace.Named#LINEAR_SRGB Linear sRGB} is provided then the
+ * corresponding extended range variant is assumed.
*
* @throws IllegalArgumentException if the width or height are <= 0, if
* Config is Config.HARDWARE (because hardware bitmaps are always
@@ -1075,22 +1080,12 @@ public final class Bitmap implements Parcelable {
if (config == Config.HARDWARE) {
throw new IllegalArgumentException("can't create mutable bitmap with Config.HARDWARE");
}
- if (colorSpace == null) {
+ if (colorSpace == null && config != Config.ALPHA_8) {
throw new IllegalArgumentException("can't create bitmap without a color space");
}
- if (config != Config.ARGB_8888) {
- if (config == Config.RGBA_F16) {
- // FIXME: This should be LINEAR_EXTENDED_SRGB, but that would fail a CTS test. See
- // b/120960866. SRGB matches the old (incorrect) behavior.
- //colorSpace = ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB);
- colorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
- } else {
- colorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
- }
- }
Bitmap bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true,
- colorSpace.getNativeInstance());
+ colorSpace == null ? 0 : colorSpace.getNativeInstance());
if (display != null) {
bm.mDensity = display.densityDpi;
@@ -1701,41 +1696,9 @@ public final class Bitmap implements Parcelable {
@Nullable
public final ColorSpace getColorSpace() {
checkRecycled("getColorSpace called on a recycled bitmap");
- // Cache the color space retrieval since it can be fairly expensive
if (mColorSpace == null) {
- if (nativeIsConfigF16(mNativePtr)) {
- // an F16 bitmaps is intended to always be linear extended, but due to
- // inconsistencies in Bitmap.create() functions it is possible to have
- // rendered into a bitmap in non-linear sRGB.
- if (nativeIsSRGB(mNativePtr)) {
- mColorSpace = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB);
- } else {
- mColorSpace = ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB);
- }
- } else if (nativeIsSRGB(mNativePtr)) {
- mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
- } else if (nativeIsSRGBLinear(mNativePtr)) {
- mColorSpace = ColorSpace.get(ColorSpace.Named.LINEAR_SRGB);
- } else {
- float[] xyz = new float[9];
- float[] params = new float[7];
-
- boolean hasColorSpace = nativeGetColorSpace(mNativePtr, xyz, params);
- if (hasColorSpace) {
- ColorSpace.Rgb.TransferParameters parameters =
- new ColorSpace.Rgb.TransferParameters(
- params[0], params[1], params[2],
- params[3], params[4], params[5], params[6]);
- ColorSpace cs = ColorSpace.match(xyz, parameters);
- if (cs != null) {
- mColorSpace = cs;
- } else {
- mColorSpace = new ColorSpace.Rgb("Unknown", xyz, parameters);
- }
- }
- }
+ mColorSpace = nativeComputeColorSpace(mNativePtr);
}
-
return mColorSpace;
}
@@ -1749,6 +1712,9 @@ public final class Bitmap implements Parcelable {
* components min/max values reduce the numerical range compared to the
* previously assigned color space.
*
+ * @throws IllegalArgumentException If the {@code Config} (returned by {@link #getConfig()})
+ * is {@link Config#ALPHA_8}.
+ *
* @param colorSpace to assign to the bitmap
*/
public void setColorSpace(@NonNull ColorSpace colorSpace) {
@@ -1756,29 +1722,47 @@ public final class Bitmap implements Parcelable {
if (colorSpace == null) {
throw new IllegalArgumentException("The colorSpace cannot be set to null");
}
- if (getColorSpace() != null) {
- if (mColorSpace.getComponentCount() != colorSpace.getComponentCount()) {
+
+ if (getConfig() == Config.ALPHA_8) {
+ throw new IllegalArgumentException("Cannot set a ColorSpace on ALPHA_8");
+ }
+
+ // Keep track of the old ColorSpace for comparison, and so we can reset it in case of an
+ // Exception.
+ final ColorSpace oldColorSpace = getColorSpace();
+ nativeSetColorSpace(mNativePtr, colorSpace.getNativeInstance());
+
+ // This will update mColorSpace. It may not be the same as |colorSpace|, e.g. if we
+ // corrected it because the Bitmap is F16.
+ mColorSpace = null;
+ final ColorSpace newColorSpace = getColorSpace();
+
+ try {
+ if (oldColorSpace.getComponentCount() != newColorSpace.getComponentCount()) {
throw new IllegalArgumentException("The new ColorSpace must have the same "
+ "component count as the current ColorSpace");
- }
- for (int i = 0; i < mColorSpace.getComponentCount(); i++) {
- if (mColorSpace.getMinValue(i) < colorSpace.getMinValue(i)) {
- throw new IllegalArgumentException("The new ColorSpace cannot increase the "
- + "minimum value for any of the components compared to the current "
- + "ColorSpace. To perform this type of conversion create a new Bitmap "
- + "in the desired ColorSpace and draw this Bitmap into it.");
- }
- if (mColorSpace.getMaxValue(i) > colorSpace.getMaxValue(i)) {
- throw new IllegalArgumentException("The new ColorSpace cannot decrease the "
- + "maximum value for any of the components compared to the current "
- + "ColorSpace/ To perform this type of conversion create a new Bitmap"
- + "in the desired ColorSpace and draw this Bitmap into it.");
+ } else {
+ for (int i = 0; i < oldColorSpace.getComponentCount(); i++) {
+ if (oldColorSpace.getMinValue(i) < newColorSpace.getMinValue(i)) {
+ throw new IllegalArgumentException("The new ColorSpace cannot increase the "
+ + "minimum value for any of the components compared to the current "
+ + "ColorSpace. To perform this type of conversion create a new "
+ + "Bitmap in the desired ColorSpace and draw this Bitmap into it.");
+ }
+ if (oldColorSpace.getMaxValue(i) > newColorSpace.getMaxValue(i)) {
+ throw new IllegalArgumentException("The new ColorSpace cannot decrease the "
+ + "maximum value for any of the components compared to the current "
+ + "ColorSpace/ To perform this type of conversion create a new "
+ + "Bitmap in the desired ColorSpace and draw this Bitmap into it.");
+ }
}
}
+ } catch (IllegalArgumentException e) {
+ // Undo the change to the ColorSpace.
+ mColorSpace = oldColorSpace;
+ nativeSetColorSpace(mNativePtr, mColorSpace.getNativeInstance());
+ throw e;
}
-
- nativeSetColorSpace(mNativePtr, colorSpace.getNativeInstance());
- mColorSpace = colorSpace;
}
/**
@@ -2197,7 +2181,6 @@ public final class Bitmap implements Parcelable {
private static native void nativeErase(long nativeBitmap, long colorSpacePtr, long color);
private static native int nativeRowBytes(long nativeBitmap);
private static native int nativeConfig(long nativeBitmap);
- private static native boolean nativeIsConfigF16(long nativeBitmap);
private static native int nativeGetPixel(long nativeBitmap, int x, int y);
private static native long nativeGetColor(long nativeBitmap, int x, int y);
@@ -2241,11 +2224,10 @@ public final class Bitmap implements Parcelable {
private static native Bitmap nativeWrapHardwareBufferBitmap(HardwareBuffer buffer,
long nativeColorSpace);
private static native GraphicBuffer nativeCreateGraphicBufferHandle(long nativeBitmap);
- private static native boolean nativeGetColorSpace(long nativePtr, float[] xyz, float[] params);
+ private static native ColorSpace nativeComputeColorSpace(long nativePtr);
private static native void nativeSetColorSpace(long nativePtr, long nativeColorSpace);
private static native boolean nativeIsSRGB(long nativePtr);
private static native boolean nativeIsSRGBLinear(long nativePtr);
- private static native void nativeCopyColorSpace(long srcBitmap, long dstBitmap);
private static native void nativeSetImmutable(long nativePtr);
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 7aff0414106a..49c3a3ba68b8 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -151,12 +151,9 @@ public class BitmapFactory {
* the decoder will pick either the color space embedded in the image
* or the color space best suited for the requested image configuration
* (for instance {@link ColorSpace.Named#SRGB sRGB} for
- * the {@link Bitmap.Config#ARGB_8888} configuration).</p>
- *
- * <p>{@link Bitmap.Config#RGBA_F16} always uses the
- * {@link ColorSpace.Named#LINEAR_EXTENDED_SRGB scRGB} color space).
- * Bitmaps in other configurations without an embedded color space are
- * assumed to be in the {@link ColorSpace.Named#SRGB sRGB} color space.</p>
+ * {@link Bitmap.Config#ARGB_8888} configuration and
+ * {@link ColorSpace.Named#EXTENDED_SRGB EXTENDED_SRGB} for
+ * {@link Bitmap.Config#RGBA_F16}).</p>
*
* <p class="note">Only {@link ColorSpace.Model#RGB} color spaces are
* currently supported. An <code>IllegalArgumentException</code> will
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index c9e46942a51a..0d5233880674 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -1475,7 +1475,7 @@ public abstract class ColorSpace {
x -> absRcpResponse(x, 1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4),
x -> absResponse(x, 1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4),
-0.799f, 2.399f,
- null, // FIXME: Use SRGB_TRANSFER_PARAMETERS
+ SRGB_TRANSFER_PARAMETERS,
Named.EXTENDED_SRGB.ordinal()
);
sNamedColorSpaces[Named.LINEAR_EXTENDED_SRGB.ordinal()] = new ColorSpace.Rgb(
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index 7ec76d79dfb1..99d8c1b42a4a 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -20,7 +20,6 @@ import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.TestApi;
import android.app.Activity;
import android.app.ActivityManager;
import android.os.IBinder;
@@ -28,13 +27,16 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
+import android.util.TimeUtils;
import android.view.FrameMetricsObserver;
import android.view.IGraphicsStats;
import android.view.IGraphicsStatsCallback;
import android.view.NativeVectorDrawableAnimator;
+import android.view.PixelCopy;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.TextureLayer;
+import android.view.animation.AnimationUtils;
import com.android.internal.util.VirtualRefBasePtr;
@@ -42,6 +44,7 @@ import java.io.File;
import java.io.FileDescriptor;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
import sun.misc.Cleaner;
@@ -50,13 +53,8 @@ import sun.misc.Cleaner;
* from {@link RenderNode}'s to an output {@link android.view.Surface}. There can be as many
* HardwareRenderer instances as desired.</p>
*
- * <h3>Threading</h3>
- * <p>HardwareRenderer is not thread safe. An instance of a HardwareRenderer must only be
- * created & used from a single thread. It does not matter what thread is used, however
- * it must have a {@link android.os.Looper}. Multiple instances do not have to share the same
- * thread, although they can.</p>
- *
* <h3>Resources & lifecycle</h3>
+ *
* <p>All HardwareRenderer instances share a common render thread. The render thread contains
* the GPU context & resources necessary to do GPU-accelerated rendering. As such, the first
* HardwareRenderer created comes with the cost of also creating the associated GPU contexts,
@@ -64,6 +62,7 @@ import sun.misc.Cleaner;
* is to have a HardwareRenderer instance for every active {@link Surface}. For example
* when an Activity shows a Dialog the system internally will use 2 hardware renderers, both
* of which may be drawing at the same time.</p>
+ *
* <p>NOTE: Due to the shared, cooperative nature of the render thread it is critical that
* any {@link Surface} used must have a prompt, reliable consuming side. System-provided
* consumers such as {@link android.view.SurfaceView},
@@ -73,8 +72,6 @@ import sun.misc.Cleaner;
* it is the app's responsibility to ensure that they consume updates promptly and rapidly.
* Failure to do so will cause the render thread to stall on that surface, blocking all
* HardwareRenderer instances.</p>
- *
- * @hide
*/
public class HardwareRenderer {
private static final String LOG_TAG = "HardwareRenderer";
@@ -89,18 +86,18 @@ public class HardwareRenderer {
* The renderer is requesting a redraw. This can occur if there's an animation that's running
* in the RenderNode tree and the hardware renderer is unable to self-animate.
*
- * If this is returned from syncAndDrawFrame the expectation is that syncAndDrawFrame
+ * <p>If this is returned from syncAndDraw the expectation is that syncAndDraw
* will be called again on the next vsync signal.
*/
public static final int SYNC_REDRAW_REQUESTED = 1 << 0;
/**
* The hardware renderer no longer has a valid {@link android.view.Surface} to render to.
- * This can happen if {@link Surface#destroy()} was called. The user should no longer
- * attempt to call syncAndDrawFrame until a new surface has been provided by calling
+ * This can happen if {@link Surface#release()} was called. The user should no longer
+ * attempt to call syncAndDraw until a new surface has been provided by calling
* setSurface.
*
- * Spoiler: the reward is GPU-accelerated drawing, better find that Surface!
+ * <p>Spoiler: the reward is GPU-accelerated drawing, better find that Surface!
*/
public static final int SYNC_LOST_SURFACE_REWARD_IF_FOUND = 1 << 1;
@@ -119,6 +116,7 @@ public class HardwareRenderer {
*/
public static final int SYNC_FRAME_DROPPED = 1 << 3;
+ /** @hide */
@IntDef(value = {
SYNC_OK, SYNC_REDRAW_REQUESTED, SYNC_LOST_SURFACE_REWARD_IF_FOUND,
SYNC_CONTEXT_IS_STOPPED, SYNC_FRAME_DROPPED})
@@ -153,7 +151,6 @@ public class HardwareRenderer {
protected RenderNode mRootNode;
private boolean mOpaque = true;
private boolean mForceDark = false;
- private FrameInfo mScratchInfo;
private boolean mIsWideGamut = false;
/**
@@ -175,14 +172,14 @@ public class HardwareRenderer {
* Destroys the rendering context of this HardwareRenderer. This destroys the resources
* associated with this renderer and releases the currently set {@link Surface}.
*
- * The renderer may be restored from this state by setting a new {@link Surface}, setting
+ * <p>The renderer may be restored from this state by setting a new {@link Surface}, setting
* new rendering content with {@link #setContentRoot(RenderNode)}, and resuming
- * rendering with {@link #syncAndDrawFrame(long)}.
+ * rendering by issuing a new {@link FrameRenderRequest}.
*
- * It is suggested to call this in response to callbacks such as
+ * <p>It is suggested to call this in response to callbacks such as
* {@link android.view.SurfaceHolder.Callback#surfaceDestroyed(SurfaceHolder)}.
*
- * Note that if there are any outstanding frame commit callbacks they may end up never being
+ * <p>Note that if there are any outstanding frame commit callbacks they may never being
* invoked if the frame was deferred to a later vsync.
*/
public void destroy() {
@@ -204,14 +201,14 @@ public class HardwareRenderer {
* Sets the center of the light source. The light source point controls the directionality
* and shape of shadows rendered by RenderNode Z & elevation.
*
- * The platform's recommendation is to set lightX to 'displayWidth / 2f - windowLeft', set
+ * <p>The platform's recommendation is to set lightX to 'displayWidth / 2f - windowLeft', set
* lightY to 0 - windowTop, lightZ set to 600dp, and lightRadius to 800dp.
*
- * The light source should be setup both as part of initial configuration, and whenever
+ * <p>The light source should be setup both as part of initial configuration, and whenever
* the window moves to ensure the light source stays anchored in display space instead
* of in window space.
*
- * This must be set at least once along with {@link #setLightSourceAlpha(float, float)}
+ * <p>This must be set at least once along with {@link #setLightSourceAlpha(float, float)}
* before shadows will work.
*
* @param lightX The X position of the light source
@@ -233,10 +230,10 @@ public class HardwareRenderer {
* Configures the ambient & spot shadow alphas. This is the alpha used when the shadow
* has max alpha, and ramps down from the values provided to zero.
*
- * These values are typically provided by the current theme, see
+ * <p>These values are typically provided by the current theme, see
* {@link android.R.attr#spotShadowAlpha} and {@link android.R.attr#ambientShadowAlpha}.
*
- * This must be set at least once along with
+ * <p>This must be set at least once along with
* {@link #setLightSourceGeometry(float, float, float, float)} before shadows will work.
*
* @param ambientShadowAlpha The alpha for the ambient shadow. If unsure, a reasonable default
@@ -254,8 +251,8 @@ public class HardwareRenderer {
/**
* Sets the content root to render. It is not necessary to call this whenever the content
* recording changes. Any mutations to the RenderNode content, or any of the RenderNode's
- * contained within the content node, will be applied whenever {@link #syncAndDrawFrame(long)}
- * is called.
+ * contained within the content node, will be applied whenever a new {@link FrameRenderRequest}
+ * is issued via {@link #createRenderRequest()} and {@link FrameRenderRequest#syncAndDraw()}.
*
* @param content The content to set as the root RenderNode. If null the content root is removed
* and the renderer will draw nothing.
@@ -295,53 +292,133 @@ public class HardwareRenderer {
}
/**
- * Syncs the RenderNode tree to the render thread and requests a frame to be drawn.
- *
- * @hide
+ * Sets the parameters that can be used to control a render request for a
+ * {@link HardwareRenderer}. This is not thread-safe and must not be held on to for longer
+ * than a single frame request.
*/
- @SyncAndDrawResult
- public int syncAndDrawFrame(@NonNull FrameInfo frameInfo) {
- return nSyncAndDrawFrame(mNativeProxy, frameInfo.frameInfo, frameInfo.frameInfo.length);
+ public final class FrameRenderRequest {
+ private FrameInfo mFrameInfo = new FrameInfo();
+ private boolean mWaitForPresent;
+
+ private FrameRenderRequest() { }
+
+ private void reset() {
+ mWaitForPresent = false;
+ // Default to the animation time which, if choreographer is in play, will default to the
+ // current vsync time. Otherwise it will be 'now'.
+ mRenderRequest.setVsyncTime(
+ AnimationUtils.currentAnimationTimeMillis() * TimeUtils.NANOS_PER_MS);
+ }
+
+ /** @hide */
+ public void setFrameInfo(FrameInfo info) {
+ System.arraycopy(info.frameInfo, 0, mFrameInfo.frameInfo, 0, info.frameInfo.length);
+ }
+
+ /**
+ * Sets the vsync time that represents the start point of this frame. Typically this
+ * comes from {@link android.view.Choreographer.FrameCallback}. Other compatible time
+ * sources include {@link System#nanoTime()}, however if the result is being displayed
+ * on-screen then using {@link android.view.Choreographer} is strongly recommended to
+ * ensure smooth animations.
+ *
+ * <p>If the clock source is not from a CLOCK_MONOTONIC source then any animations driven
+ * directly by RenderThread will not be synchronized properly with the current frame.
+ *
+ * @param vsyncTime The vsync timestamp for this frame. The timestamp is in nanoseconds
+ * and should come from a CLOCK_MONOTONIC source.
+ *
+ * @return this instance
+ */
+ public FrameRenderRequest setVsyncTime(long vsyncTime) {
+ mFrameInfo.setVsync(vsyncTime, vsyncTime);
+ mFrameInfo.addFlags(FrameInfo.FLAG_SURFACE_CANVAS);
+ return this;
+ }
+
+ /**
+ * Adds a frame commit callback. This callback will be invoked when the current rendering
+ * content has been rendered into a frame and submitted to the swap chain. The frame may
+ * not currently be visible on the display when this is invoked, but it has been submitted.
+ * This callback is useful in combination with {@link PixelCopy} to capture the current
+ * rendered content of the UI reliably.
+ *
+ * @param executor The executor to run the callback on. It is strongly recommended that
+ * this executor post to a different thread, as the calling thread is
+ * highly sensitive to being blocked.
+ * @param frameCommitCallback The callback to invoke when the frame content has been drawn.
+ * Will be invoked on the given {@link Executor}.
+ *
+ * @return this instance
+ */
+ public FrameRenderRequest setFrameCommitCallback(@NonNull Executor executor,
+ @NonNull Runnable frameCommitCallback) {
+ setFrameCompleteCallback(frameNr -> executor.execute(frameCommitCallback));
+ return this;
+ }
+
+ /**
+ * Sets whether or not {@link #syncAndDraw()} should block until the frame has been
+ * presented. If this is true and {@link #syncAndDraw()} does not return
+ * {@link #SYNC_FRAME_DROPPED} or an error then when {@link #syncAndDraw()} has returned
+ * the frame has been submitted to the {@link Surface}. The default and typically
+ * recommended value is false, as blocking for present will prevent pipelining from
+ * happening, reducing overall throughput. This is useful for situations such as
+ * {@link SurfaceHolder.Callback2#surfaceRedrawNeeded(SurfaceHolder)} where it is desired
+ * to block until a frame has been presented to ensure first-frame consistency with
+ * other Surfaces.
+ *
+ * @param shouldWait If true the next call to {@link #syncAndDraw()} will block until
+ * completion.
+ * @return this instance
+ */
+ public FrameRenderRequest setWaitForPresent(boolean shouldWait) {
+ mWaitForPresent = shouldWait;
+ return this;
+ }
+
+ /**
+ * Syncs the RenderNode tree to the render thread and requests a frame to be drawn. This
+ * {@link FrameRenderRequest} instance should no longer be used after calling this method.
+ * The system internally may reuse instances of {@link FrameRenderRequest} to reduce
+ * allocation churn.
+ *
+ * @return The result of the sync operation. See {@link SyncAndDrawResult}.
+ */
+ @SyncAndDrawResult
+ public int syncAndDraw() {
+ int syncResult = syncAndDrawFrame(mFrameInfo);
+ if (mWaitForPresent && (syncResult & SYNC_FRAME_DROPPED) == 0) {
+ fence();
+ }
+ return syncResult;
+ }
}
+ private FrameRenderRequest mRenderRequest = new FrameRenderRequest();
+
/**
- * Syncs the RenderNode tree to the render thread and requests a frame to be drawn.
+ * Returns a {@link FrameRenderRequest} that can be used to render a new frame. This is used
+ * to synchronize the RenderNode content provided by {@link #setContentRoot(RenderNode)} with
+ * the RenderThread and then renders a single frame to the Surface set with
+ * {@link #setSurface(Surface)}.
*
- * @param vsyncTime The vsync timestamp for this frame. Typically this comes from
- * {@link android.view.Choreographer.FrameCallback}. Must be set and be valid
- * as the renderer uses this time internally to drive animations.
- * @return The result of the sync operation. See {@link SyncAndDrawResult}.
+ * @return An instance of {@link FrameRenderRequest}. The instance may be reused for every
+ * frame, so the caller should not hold onto it for longer than a single render request.
*/
- @SyncAndDrawResult
- public int syncAndDrawFrame(long vsyncTime) {
- if (mScratchInfo == null) {
- mScratchInfo = new FrameInfo();
- }
- mScratchInfo.setVsync(vsyncTime, vsyncTime);
- mScratchInfo.addFlags(FrameInfo.FLAG_SURFACE_CANVAS);
- return syncAndDrawFrame(mScratchInfo);
+ public FrameRenderRequest createRenderRequest() {
+ mRenderRequest.reset();
+ return mRenderRequest;
}
/**
* Syncs the RenderNode tree to the render thread and requests a frame to be drawn.
- * frameCommitCallback callback will be invoked when the current rendering content has been
- * rendered into a frame and submitted to the swap chain.
*
- * @param vsyncTime The vsync timestamp for this frame. Typically this comes from
- * {@link android.view.Choreographer.FrameCallback}. Must be set and
- * be valid as the renderer uses this time internally to drive
- * animations.
- * @param frameCommitCallback The callback to invoke when the frame content has been drawn.
- * Will be invoked on the current {@link android.os.Looper} thread.
- * @return The result of the sync operation. See {@link SyncAndDrawResult}.
+ * @hide
*/
@SyncAndDrawResult
- public int syncAndDrawFrame(long vsyncTime,
- @Nullable Runnable frameCommitCallback) {
- if (frameCommitCallback != null) {
- setFrameCompleteCallback(frameNr -> frameCommitCallback.run());
- }
- return syncAndDrawFrame(vsyncTime);
+ public int syncAndDrawFrame(@NonNull FrameInfo frameInfo) {
+ return nSyncAndDrawFrame(mNativeProxy, frameInfo.frameInfo, frameInfo.frameInfo.length);
}
/**
@@ -349,10 +426,11 @@ public class HardwareRenderer {
* is useful to temporarily suspend using the active Surface in order to do any Surface
* mutations necessary.
*
- * Any subsequent draws will override the pause, resuming normal operation.
+ * <p>Any subsequent draws will override the pause, resuming normal operation.
*
* @return true if there was an outstanding render request, false otherwise. If this is true
- * the caller should ensure that {@link #syncAndDrawFrame(long)} is called at the soonest
+ * the caller should ensure that {@link #createRenderRequest()}
+ * and {@link FrameRenderRequest#syncAndDraw()} is called at the soonest
* possible time to resume normal operation.
*
* TODO Should this be exposed? ViewRootImpl needs it because it destroys the old
@@ -367,14 +445,14 @@ public class HardwareRenderer {
/**
* Hard stops rendering into the surface. If the renderer is stopped it will
- * block any attempt to render. Calls to {@link #syncAndDrawFrame(long)} will still
- * sync over the latest rendering content, however they will not render and instead
+ * block any attempt to render. Calls to {@link FrameRenderRequest#syncAndDraw()} will
+ * still sync over the latest rendering content, however they will not render and instead
* {@link #SYNC_CONTEXT_IS_STOPPED} will be returned.
*
- * If false is passed then rendering will resume as normal. Any pending rendering requests
+ * <p>If false is passed then rendering will resume as normal. Any pending rendering requests
* will produce a new frame at the next vsync signal.
*
- * This is useful in combination with lifecycle events such as {@link Activity#onStop()}
+ * <p>This is useful in combination with lifecycle events such as {@link Activity#onStop()}
* and {@link Activity#onStart()}.
*
* @param stopped true to stop all rendering, false to resume
@@ -384,24 +462,26 @@ public class HardwareRenderer {
}
/**
- * Destroys all hardware rendering resources associated with the current rendering content.
+ * Destroys all the display lists associated with the current rendering content.
* This includes releasing a reference to the current content root RenderNode. It will
* therefore be necessary to call {@link #setContentRoot(RenderNode)} in order to resume
- * rendering after calling this.
+ * rendering after calling this, along with re-recording the display lists for the
+ * RenderNode tree.
*
- * It is recommended, but not necessary, to use this in combination with lifecycle events
+ * <p>It is recommended, but not necessary, to use this in combination with lifecycle events
* such as {@link Activity#onStop()} and {@link Activity#onStart()} or in response to
* {@link android.content.ComponentCallbacks2#onTrimMemory(int)} signals such as
* {@link android.content.ComponentCallbacks2#TRIM_MEMORY_UI_HIDDEN}
*
* See also {@link #setStopped(boolean)}
*/
- public void destroyHardwareResources() {
+ public void clearContent() {
nDestroyHardwareResources(mNativeProxy);
}
/**
* Whether or not the force-dark feature should be used for this renderer.
+ * @hide
*/
public boolean setForceDark(boolean enable) {
if (mForceDark != enable) {
@@ -415,20 +495,24 @@ public class HardwareRenderer {
/**
* Allocate buffers ahead of time to avoid allocation delays during rendering.
*
- * Typically a Surface will allocate buffers lazily. This is usually fine and reduces the
+ * <p>Typically a Surface will allocate buffers lazily. This is usually fine and reduces the
* memory usage of Surfaces that render rarely or never hit triple buffering. However
* for UI it can result in a slight bit of jank on first launch. This hint will
* tell the HardwareRenderer that now is a good time to allocate the 3 buffers
* necessary for typical rendering.
*
- * Must be called after a {@link Surface} has been set.
+ * <p>Must be called after a {@link Surface} has been set.
+ *
+ * TODO: Figure out if we even need/want this. Should HWUI just be doing this in response
+ * to setSurface anyway? Vulkan swapchain makes this murky, so delay making it public
+ * @hide
*/
public void allocateBuffers() {
nAllocateBuffers(mNativeProxy);
}
/**
- * Notifies the hardware renderer that a call to {@link #syncAndDrawFrame(long)} will
+ * Notifies the hardware renderer that a call to {@link FrameRenderRequest#syncAndDraw()} will
* be coming soon. This is used to help schedule when RenderThread-driven animations will
* happen as the renderer wants to avoid producing more than one frame per vsync signal.
*/
@@ -439,7 +523,7 @@ public class HardwareRenderer {
/**
* Change the HardwareRenderer's opacity. Will take effect on the next frame produced.
*
- * If the renderer is set to opaque it is the app's responsibility to ensure that the
+ * <p>If the renderer is set to opaque it is the app's responsibility to ensure that the
* content renders to every pixel of the Surface, otherwise corruption may result. Note that
* this includes ensuring that the first draw of any given pixel does not attempt to blend
* against the destination. If this is false then the hardware renderer will clear to
@@ -527,7 +611,7 @@ public class HardwareRenderer {
}
/**
- * Prevents any further drawing until {@link #syncAndDrawFrame(long)} is called.
+ * Prevents any further drawing until {@link FrameRenderRequest#syncAndDraw()} is called.
* This is a signal that the contents of the RenderNode tree are no longer safe to play back.
* In practice this usually means that there are Functor pointers in the
* display list that are no longer valid.
@@ -718,10 +802,8 @@ public class HardwareRenderer {
* Interface for listening to picture captures
* @hide
*/
- @TestApi
public interface PictureCapturedCallback {
/** @hide */
- @TestApi
void onPictureCaptured(Picture picture);
}
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index d913c6694bd5..9b5e33017743 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -1556,12 +1556,9 @@ public final class ImageDecoder implements AutoCloseable {
* decoder will pick either the color space embedded in the image or the
* {@link ColorSpace} best suited for the requested image configuration
* (for instance {@link ColorSpace.Named#SRGB sRGB} for the
- * {@link Bitmap.Config#ARGB_8888} configuration).</p>
- *
- * <p>{@link Bitmap.Config#RGBA_F16} always uses the
- * {@link ColorSpace.Named#LINEAR_EXTENDED_SRGB scRGB} color space.
- * Bitmaps in other configurations without an embedded color space are
- * assumed to be in the {@link ColorSpace.Named#SRGB sRGB} color space.</p>
+ * {@link Bitmap.Config#ARGB_8888} configuration and
+ * {@link ColorSpace.Named#EXTENDED_SRGB EXTENDED_SRGB} for
+ * {@link Bitmap.Config#RGBA_F16}).</p>
*
* <p class="note">Only {@link ColorSpace.Model#RGB} color spaces are
* currently supported. An <code>IllegalArgumentException</code> will
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 7c9529b8ff71..ef9255f66695 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -127,7 +127,10 @@ public class Typeface {
static Typeface sDefaultTypeface;
// Following two fields are not used but left for hiddenapi private list
- @UnsupportedAppUsage
+ /**
+ * Use {@link SystemFonts#getAvailableFonts()} instead.
+ */
+ @UnsupportedAppUsage(trackingBug = 123769347)
static final Map<String, Typeface> sSystemFontMap;
// We cannot support sSystemFallbackMap since we will migrate to public FontFamily API.
@@ -175,7 +178,12 @@ public class Typeface {
private int[] mSupportedAxes;
private static final int[] EMPTY_AXES = {};
- @UnsupportedAppUsage
+ /**
+ * Please use font in xml and also your application global theme to change the default Typeface.
+ * android:textViewStyle and its attribute android:textAppearance can be used in order to change
+ * typeface and other text related properties.
+ */
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private static void setDefault(Typeface t) {
sDefaultTypeface = t;
nativeSetDefault(t.native_instance);
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 789e38c4e650..d7aee7767524 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -43,6 +43,7 @@ import android.graphics.RecordingCanvas;
import android.graphics.Rect;
import android.graphics.RenderNode;
import android.os.Build;
+import android.os.Handler;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.IntArray;
@@ -1241,6 +1242,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
// If the duration of an animation is more than 300 frames, we cap the sample size to 300.
private static final int MAX_SAMPLE_POINTS = 300;
+ private Handler mHandler;
private AnimatorListener mListener = null;
private final LongArray mStartDelays = new LongArray();
private PropertyValuesHolder.PropertyValues mTmpValues =
@@ -1671,6 +1673,9 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
.mRootName);
}
mStarted = true;
+ if (mHandler == null) {
+ mHandler = new Handler();
+ }
nStart(mSetPtr, this, ++mLastListenerId);
invalidateOwningView();
if (mListener != null) {
@@ -1780,7 +1785,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
// onFinished: should be called from native
@UnsupportedAppUsage
private static void callOnFinished(VectorDrawableAnimatorRT set, int id) {
- set.onAnimationEnd(id);
+ set.mHandler.post(() -> set.onAnimationEnd(id));
}
private void transferPendingActions(VectorDrawableAnimator animatorSet) {
diff --git a/graphics/java/android/graphics/drawable/ColorStateListDrawable.java b/graphics/java/android/graphics/drawable/ColorStateListDrawable.java
index c0c6a4f424a1..5181d8992be5 100644
--- a/graphics/java/android/graphics/drawable/ColorStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorStateListDrawable.java
@@ -157,28 +157,22 @@ public class ColorStateListDrawable extends Drawable implements Drawable.Callbac
@Override
public void invalidateDrawable(Drawable who) {
- final Callback callback = getCallback();
-
- if (callback != null) {
- callback.invalidateDrawable(who);
+ if (who == mColorDrawable && getCallback() != null) {
+ getCallback().invalidateDrawable(this);
}
}
@Override
public void scheduleDrawable(Drawable who, Runnable what, long when) {
- final Callback callback = getCallback();
-
- if (callback != null) {
- callback.scheduleDrawable(who, what, when);
+ if (who == mColorDrawable && getCallback() != null) {
+ getCallback().scheduleDrawable(this, what, when);
}
}
@Override
public void unscheduleDrawable(Drawable who, Runnable what) {
- final Callback callback = getCallback();
-
- if (callback != null) {
- callback.unscheduleDrawable(who, what);
+ if (who == mColorDrawable && getCallback() != null) {
+ getCallback().unscheduleDrawable(this, what);
}
}
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 991847ad27fa..6ecb62140532 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -44,6 +44,7 @@ import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.graphics.Xfermode;
+import android.os.Build;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -156,12 +157,12 @@ public class GradientDrawable extends Drawable {
private static final float DEFAULT_INNER_RADIUS_RATIO = 3.0f;
private static final float DEFAULT_THICKNESS_RATIO = 9.0f;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
private GradientState mGradientState;
@UnsupportedAppUsage
private final Paint mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124051827)
private Rect mPadding;
@UnsupportedAppUsage
private Paint mStrokePaint; // optional, set by the caller
@@ -670,7 +671,28 @@ public class GradientDrawable extends Drawable {
* @see #setColor(int)
*/
public void setColors(@ColorInt int[] colors) {
+ setColors(colors, null);
+ }
+
+ /**
+ * Sets the colors and offsets used to draw the gradient.
+ * <p>
+ * Each color is specified as an ARGB integer and the array must contain at
+ * least 2 colors.
+ * <p>
+ * <strong>Note</strong>: changing colors will affect all instances of a
+ * drawable loaded from a resource. It is recommended to invoke
+ * {@link #mutate()} before changing the colors.
+ *
+ * @param colors an array containing 2 or more ARGB colors
+ * @param offsets optional array of floating point parameters representing the positions
+ * of the colors. Null evenly disperses the colors
+ * @see #mutate()
+ * @see #setColors(int[])
+ */
+ public void setColors(@ColorInt int[] colors, @Nullable float[] offsets) {
mGradientState.setGradientColors(colors);
+ mGradientState.mPositions = offsets;
mGradientIsDirty = true;
invalidateSelf();
}
@@ -849,6 +871,115 @@ public class GradientDrawable extends Drawable {
}
}
+ /**
+ * Inner radius of the ring expressed as a ratio of the ring's width.
+ *
+ * @see #getInnerRadiusRatio()
+ * @attr ref android.R.styleable#GradientDrawable_innerRadiusRatio
+ */
+ public void setInnerRadiusRatio(float innerRadiusRatio) {
+ mGradientState.mInnerRadiusRatio = innerRadiusRatio;
+ mPathIsDirty = true;
+ invalidateSelf();
+ }
+
+ /**
+ * Return the inner radius of the ring expressed as a ratio of the ring's width.
+ *
+ * @see #setInnerRadiusRatio(float)
+ * @attr ref android.R.styleable#GradientDrawable_innerRadiusRatio
+ */
+ public float getInnerRadiusRatio() {
+ return mGradientState.mInnerRadiusRatio;
+ }
+
+ /**
+ * Configure the inner radius of the ring.
+ *
+ * @see #getInnerRadius()
+ * @attr ref android.R.styleable#GradientDrawable_innerRadius
+ */
+ public void setInnerRadius(int innerRadius) {
+ mGradientState.mInnerRadius = innerRadius;
+ mPathIsDirty = true;
+ invalidateSelf();
+ }
+
+ /**
+ * Retrn the inner radius of the ring
+ *
+ * @see #setInnerRadius(int)
+ * @attr ref android.R.styleable#GradientDrawable_innerRadius
+ */
+ public int getInnerRadius() {
+ return mGradientState.mInnerRadius;
+ }
+
+ /**
+ * Configure the thickness of the ring expressed as a ratio of the ring's width.
+ *
+ * @see #getThicknessRatio()
+ * @attr ref android.R.styleable#GradientDrawable_thicknessRatio
+ */
+ public void setThicknessRatio(float thicknessRatio) {
+ mGradientState.mThicknessRatio = thicknessRatio;
+ mPathIsDirty = true;
+ invalidateSelf();
+ }
+
+ /**
+ * Return the thickness ratio of the ring expressed as a ratio of the ring's width.
+ *
+ * @see #setThicknessRatio(float)
+ * @attr ref android.R.styleable#GradientDrawable_thicknessRatio
+ */
+ public float getThicknessRatio() {
+ return mGradientState.mThicknessRatio;
+ }
+
+ /**
+ * Configure the thickness of the ring.
+ *
+ * @attr ref android.R.styleable#GradientDrawable_thickness
+ */
+ public void setThickness(int thickness) {
+ mGradientState.mThickness = thickness;
+ mPathIsDirty = true;
+ invalidateSelf();
+ }
+
+ /**
+ * Return the thickness of the ring
+ *
+ * @see #setThickness(int)
+ * @attr ref android.R.styleable#GradientDrawable_thickness
+ */
+ public int getThickness() {
+ return mGradientState.mThickness;
+ }
+
+ /**
+ * Configure the padding of the gradient shape
+ * @param left Left padding of the gradient shape
+ * @param top Top padding of the gradient shape
+ * @param right Right padding of the gradient shape
+ * @param bottom Bottom padding of the gradient shape
+ *
+ * @attr ref android.R.styleable#GradientDrawablePadding_left
+ * @attr ref android.R.styleable#GradientDrawablePadding_top
+ * @attr ref android.R.styleable#GradientDrawablePadding_right
+ * @attr ref android.R.styleable#GradientDrawablePadding_bottom
+ */
+ public void setPadding(int left, int top, int right, int bottom) {
+ if (mGradientState.mPadding == null) {
+ mGradientState.mPadding = new Rect();
+ }
+
+ mGradientState.mPadding.set(left, top, right, bottom);
+ mPadding = mGradientState.mPadding;
+ invalidateSelf();
+ }
+
private Path buildRing(GradientState st) {
if (mRingPath != null && (!st.mUseLevelForShape || !mPathIsDirty)) return mRingPath;
mPathIsDirty = false;
@@ -1814,46 +1945,46 @@ public class GradientDrawable extends Drawable {
final static class GradientState extends ConstantState {
public @Config int mChangingConfigurations;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
public @Shape int mShape = RECTANGLE;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
public @GradientType int mGradient = LINEAR_GRADIENT;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
public int mAngle = 0;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
public Orientation mOrientation;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
public ColorStateList mSolidColors;
public ColorStateList mStrokeColors;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
public @ColorInt int[] mGradientColors;
public @ColorInt int[] mTempColors; // no need to copy
public float[] mTempPositions; // no need to copy
@UnsupportedAppUsage
public float[] mPositions;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
public int mStrokeWidth = -1; // if >= 0 use stroking.
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
public float mStrokeDashWidth = 0.0f;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
public float mStrokeDashGap = 0.0f;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
public float mRadius = 0.0f; // use this if mRadiusArray is null
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
public float[] mRadiusArray = null;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
public Rect mPadding = null;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
public int mWidth = -1;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
public int mHeight = -1;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
public float mInnerRadiusRatio = DEFAULT_INNER_RADIUS_RATIO;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050218)
public float mThicknessRatio = DEFAULT_THICKNESS_RATIO;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050917)
public int mInnerRadius = -1;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050218)
public int mThickness = -1;
public boolean mDither = false;
public Insets mOpticalInsets = Insets.NONE;
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 5d5e40fd3ac3..eb169be06025 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -18,8 +18,8 @@ package android.security;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
-import android.annotation.WorkerThread;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.WorkerThread;
import android.app.Activity;
import android.app.PendingIntent;
import android.app.Service;
@@ -29,7 +29,6 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.net.Uri;
import android.os.Binder;
-import android.os.Build;
import android.os.IBinder;
import android.os.Looper;
import android.os.Process;
@@ -38,6 +37,8 @@ import android.os.UserHandle;
import android.security.keystore.AndroidKeyStoreProvider;
import android.security.keystore.KeyProperties;
+import com.android.org.conscrypt.TrustedCertificateStore;
+
import java.io.ByteArrayInputStream;
import java.io.Closeable;
import java.io.Serializable;
@@ -58,8 +59,6 @@ import java.util.concurrent.LinkedBlockingQueue;
import javax.security.auth.x500.X500Principal;
-import com.android.org.conscrypt.TrustedCertificateStore;
-
/**
* The {@code KeyChain} class provides access to private keys and
* their corresponding certificate chains in credential storage.
@@ -214,8 +213,8 @@ public final class KeyChain {
*
* @deprecated Use {@link #ACTION_KEYCHAIN_CHANGED}, {@link #ACTION_TRUST_STORE_CHANGED} or
* {@link #ACTION_KEY_ACCESS_CHANGED}. Apps that target a version higher than
- * {@link Build.VERSION_CODES#N_MR1} will only receive this broadcast if they register for it
- * at runtime.
+ * {@link android.os.Build.VERSION_CODES#N_MR1} will only receive this broadcast if they
+ * register for it at runtime.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_STORAGE_CHANGED = "android.security.STORAGE_CHANGED";
@@ -532,8 +531,8 @@ public final class KeyChain {
}
/**
- * Returns the {@code PrivateKey} for the requested alias, or null
- * if there is no result.
+ * Returns the {@code PrivateKey} for the requested alias, or null if the alias does not exist
+ * or the caller has no permission to access it (see note on exceptions below).
*
* <p> This method may block while waiting for a connection to another process, and must never
* be called from the main thread.
@@ -541,6 +540,15 @@ public final class KeyChain {
* at any time from the main thread, it is safer to rely on a long-lived context such as one
* returned from {@link Context#getApplicationContext()}.
*
+ * <p> If the caller provides a valid alias to which it was not granted access, then the
+ * caller must invoke {@link #choosePrivateKeyAlias} again to get another valid alias
+ * or a grant to access the same alias.
+ * <p>On Android versions prior to Q, when a key associated with the specified alias is
+ * unavailable, the method will throw a {@code KeyChainException} rather than return null.
+ * If the exception's cause (as obtained by calling {@code KeyChainException.getCause()})
+ * is a throwable of type {@code IllegalStateException} then the caller lacks a grant
+ * to access the key and certificates associated with this alias.
+ *
* @param alias The alias of the desired private key, typically returned via
* {@link KeyChainAliasCallback#alias}.
* @throws KeyChainException if the alias was valid but there was some problem accessing it.
@@ -591,8 +599,10 @@ public final class KeyChain {
}
/**
- * Returns the {@code X509Certificate} chain for the requested
- * alias, or null if there is no result.
+ * Returns the {@code X509Certificate} chain for the requested alias, or null if the alias
+ * does not exist or the caller has no permission to access it (see note on exceptions
+ * in {@link #getPrivateKey}).
+ *
* <p>
* <strong>Note:</strong> If a certificate chain was explicitly specified when the alias was
* installed, this method will return that chain. If only the client certificate was specified
@@ -604,6 +614,9 @@ public final class KeyChain {
* <p> As {@link Activity} and {@link Service} contexts are short-lived and can be destroyed
* at any time from the main thread, it is safer to rely on a long-lived context such as one
* returned from {@link Context#getApplicationContext()}.
+ * <p> In case the caller specifies an alias for which it lacks a grant, it must call
+ * {@link #choosePrivateKeyAlias} again. See {@link #getPrivateKey} for more details on
+ * coping with this scenario.
*
* @param alias The alias of the desired certificate chain, typically
* returned via {@link KeyChainAliasCallback#alias}.
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 81afd937d85e..66d8542553d2 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -203,6 +203,27 @@ const DynamicRefTable* AssetManager2::GetDynamicRefTableForCookie(ApkAssetsCooki
return nullptr;
}
+const std::unordered_map<std::string, std::string>*
+ AssetManager2::GetOverlayableMapForPackage(uint32_t package_id) const {
+
+ if (package_id >= package_ids_.size()) {
+ return nullptr;
+ }
+
+ const size_t idx = package_ids_[package_id];
+ if (idx == 0xff) {
+ return nullptr;
+ }
+
+ const PackageGroup& package_group = package_groups_[idx];
+ if (package_group.packages_.size() == 0) {
+ return nullptr;
+ }
+
+ const auto loaded_package = package_group.packages_[0].loaded_package_;
+ return &loaded_package->GetOverlayableMap();
+}
+
void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
const int diff = configuration_.diff(configuration);
configuration_ = configuration;
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index bdd47061054a..72873abc6a42 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -598,6 +598,13 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
std::string actor;
util::ReadUtf16StringFromDevice(header->actor, arraysize(header->actor), &actor);
+ if (loaded_package->overlayable_map_.find(name) !=
+ loaded_package->overlayable_map_.end()) {
+ LOG(ERROR) << "Multiple <overlayable> blocks with the same name '" << name << "'.";
+ return {};
+ }
+ loaded_package->overlayable_map_.emplace(name, actor);
+
// Iterate over the overlayable policy chunks contained within the overlayable chunk data
ChunkIterator overlayable_iter(child_chunk.data_ptr(), child_chunk.data_size());
while (overlayable_iter.HasNext()) {
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index d862182d8960..fc5aa9c7f1b9 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -124,6 +124,9 @@ class AssetManager2 {
// This may be nullptr if the APK represented by `cookie` has no resource table.
const DynamicRefTable* GetDynamicRefTableForCookie(ApkAssetsCookie cookie) const;
+ const std::unordered_map<std::string, std::string>*
+ GetOverlayableMapForPackage(uint32_t package_id) const;
+
// Sets/resets the configuration for this AssetManager. This will cause all
// caches that are related to the configuration change to be invalidated.
void SetConfiguration(const ResTable_config& configuration);
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index b5f4006dbb00..950f5413f550 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -20,6 +20,7 @@
#include <memory>
#include <set>
#include <vector>
+#include <unordered_map>
#include <unordered_set>
#include "android-base/macros.h"
@@ -242,6 +243,10 @@ class LoadedPackage {
return defines_overlayable_;
}
+ const std::unordered_map<std::string, std::string>& GetOverlayableMap() const {
+ return overlayable_map_;
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(LoadedPackage);
@@ -261,6 +266,7 @@ class LoadedPackage {
ByteBucketArray<uint32_t> resource_ids_;
std::vector<DynamicPackageEntry> dynamic_package_map_;
std::vector<const std::pair<OverlayableInfo, std::unordered_set<uint32_t>>> overlayable_infos_;
+ std::unordered_map<std::string, std::string> overlayable_map_;
};
// Read-only view into a resource table. This class validates all data
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index 447fdf5d306a..40c8e46e4d84 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -71,6 +71,9 @@ class AssetManager2Test : public ::testing::Test {
app_assets_ = ApkAssets::Load(GetTestDataPath() + "/app/app.apk");
ASSERT_THAT(app_assets_, NotNull());
+
+ overlayable_assets_ = ApkAssets::Load(GetTestDataPath() + "/overlayable/overlayable.apk");
+ ASSERT_THAT(overlayable_assets_, NotNull());
}
protected:
@@ -83,6 +86,7 @@ class AssetManager2Test : public ::testing::Test {
std::unique_ptr<const ApkAssets> appaslib_assets_;
std::unique_ptr<const ApkAssets> system_assets_;
std::unique_ptr<const ApkAssets> app_assets_;
+ std::unique_ptr<const ApkAssets> overlayable_assets_;
};
TEST_F(AssetManager2Test, FindsResourceFromSingleApkAssets) {
@@ -703,4 +707,20 @@ TEST_F(AssetManager2Test, GetLastPathAfterDisablingReturnsEmpty) {
EXPECT_EQ("", resultDisabled);
}
+TEST_F(AssetManager2Test, GetOverlayableMap) {
+ ResTable_config desired_config;
+ memset(&desired_config, 0, sizeof(desired_config));
+
+ AssetManager2 assetmanager;
+ assetmanager.SetResourceResolutionLoggingEnabled(true);
+ assetmanager.SetConfiguration(desired_config);
+ assetmanager.SetApkAssets({overlayable_assets_.get()});
+
+ const auto map = assetmanager.GetOverlayableMapForPackage(0x7f);
+ ASSERT_NE(nullptr, map);
+ ASSERT_EQ(2, map->size());
+ ASSERT_EQ(map->at("OverlayableResources1"), "overlay://theme");
+ ASSERT_EQ(map->at("OverlayableResources2"), "overlay://com.android.overlayable");
+}
+
} // namespace android
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index b8d3c6bf92fb..d58e8d20c8aa 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -331,7 +331,7 @@ TEST(LoadedArscTest, ResourceIdentifierIterator) {
const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
ASSERT_EQ(1u, packages.size());
- EXPECT_EQ(std::string("com.android.basic"), packages[0]->GetPackageName());
+ ASSERT_EQ(std::string("com.android.basic"), packages[0]->GetPackageName());
const auto& loaded_package = packages[0];
auto iter = loaded_package->begin();
@@ -369,6 +369,24 @@ TEST(LoadedArscTest, ResourceIdentifierIterator) {
ASSERT_EQ(end, iter);
}
+TEST(LoadedArscTest, GetOverlayableMap) {
+ std::string contents;
+ ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlayable/overlayable.apk",
+ "resources.arsc", &contents));
+
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ ASSERT_NE(nullptr, loaded_arsc);
+
+ const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
+ ASSERT_EQ(1u, packages.size());
+ ASSERT_EQ(std::string("com.android.overlayable"), packages[0]->GetPackageName());
+
+ const auto map = packages[0]->GetOverlayableMap();
+ ASSERT_EQ(2, map.size());
+ ASSERT_EQ(map.at("OverlayableResources1"), "overlay://theme");
+ ASSERT_EQ(map.at("OverlayableResources2"), "overlay://com.android.overlayable");
+}
+
// structs with size fields (like Res_value, ResTable_entry) should be
// backwards and forwards compatible (aka checking the size field against
// sizeof(Res_value) might not be backwards compatible.
diff --git a/libs/hwui/FrameMetricsObserver.h b/libs/hwui/FrameMetricsObserver.h
index 237fc622dd2e..b93f07853242 100644
--- a/libs/hwui/FrameMetricsObserver.h
+++ b/libs/hwui/FrameMetricsObserver.h
@@ -23,7 +23,7 @@ namespace uirenderer {
class FrameMetricsObserver : public VirtualLightRefBase {
public:
- virtual void notify(const int64_t* buffer);
+ virtual void notify(const int64_t* buffer) = 0;
};
} // namespace uirenderer
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 76c56609ef47..2ffda839c210 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -107,7 +107,7 @@ CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, Matrix4& texTran
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
mRenderThread.requireGlContext();
} else {
- mRenderThread.vulkanManager().initialize();
+ mRenderThread.requireVkContext();
}
if (!image.get()) {
return CopyResult::UnknownError;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 15f53f286261..87cffb52c150 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -120,7 +120,7 @@ bool SkiaVulkanPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect
}
DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() {
- mVkManager.initialize();
+ mRenderThread.requireVkContext();
return new DeferredLayerUpdater(mRenderThread.renderState());
}
@@ -136,8 +136,9 @@ bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBeh
setSurfaceColorProperties(colorMode);
if (surface) {
+ mRenderThread.requireVkContext();
mVkSurface = mVkManager.createSurface(surface, colorMode, mSurfaceColorSpace,
- mSurfaceColorType);
+ mSurfaceColorType, mRenderThread.getGrContext());
}
return mVkSurface != nullptr;
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 3904ed20fd77..fc63819120d6 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -173,10 +173,10 @@ void RenderThread::initThreadLocals() {
initializeDisplayEventReceiver();
mEglManager = new EglManager();
mRenderState = new RenderState(*this);
- mVkManager = new VulkanManager(*this);
+ mVkManager = new VulkanManager();
mCacheManager = new CacheManager(mDisplayInfo);
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
- mVkManager->initialize();
+ requireVkContext();
}
}
@@ -195,8 +195,7 @@ void RenderThread::requireGlContext() {
LOG_ALWAYS_FATAL_IF(!glInterface.get());
GrContextOptions options;
- options.fPreferExternalImagesOverES3 = true;
- options.fDisableDistanceFieldPaths = true;
+ initGrContextOptions(options);
auto glesVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
auto size = glesVersion ? strlen(glesVersion) : -1;
cacheManager().configureContext(&options, glesVersion, size);
@@ -205,6 +204,25 @@ void RenderThread::requireGlContext() {
setGrContext(grContext);
}
+void RenderThread::requireVkContext() {
+ if (mVkManager->hasVkContext()) {
+ return;
+ }
+ mVkManager->initialize();
+ GrContextOptions options;
+ initGrContextOptions(options);
+ // TODO: get a string describing the SPIR-V compiler version and use it here
+ cacheManager().configureContext(&options, nullptr, 0);
+ sk_sp<GrContext> grContext = mVkManager->createContext(options);
+ LOG_ALWAYS_FATAL_IF(!grContext.get());
+ setGrContext(grContext);
+}
+
+void RenderThread::initGrContextOptions(GrContextOptions& options) {
+ options.fPreferExternalImagesOverES3 = true;
+ options.fDisableDistanceFieldPaths = true;
+}
+
void RenderThread::destroyRenderingContext() {
mFunctorManager.onContextDestroyed();
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index b18292820c6b..419e7c7a6b51 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -112,6 +112,7 @@ public:
void dumpGraphicsMemory(int fd);
void requireGlContext();
+ void requireVkContext();
void destroyRenderingContext();
/**
@@ -122,6 +123,8 @@ public:
*/
static bool isCurrent();
+ static void initGrContextOptions(GrContextOptions& options);
+
protected:
virtual bool threadLoop() override;
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 90397fddf618..1e685abd8afa 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -55,11 +55,7 @@ static void free_features_extensions_structs(const VkPhysicalDeviceFeatures2& fe
#define GET_INST_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(mInstance, "vk" #F)
#define GET_DEV_PROC(F) m##F = (PFN_vk##F)vkGetDeviceProcAddr(mDevice, "vk" #F)
-VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) {}
-
void VulkanManager::destroy() {
- mRenderThread.setGrContext(nullptr);
-
// We don't need to explicitly free the command buffer since it automatically gets freed when we
// delete the VkCommandPool below.
mDummyCB = VK_NULL_HANDLE;
@@ -333,29 +329,10 @@ void VulkanManager::initialize() {
LOG_ALWAYS_FATAL_IF(mEnumerateInstanceVersion(&instanceVersion));
LOG_ALWAYS_FATAL_IF(instanceVersion < VK_MAKE_VERSION(1, 1, 0));
- GrVkExtensions extensions;
- this->setupDevice(extensions, mPhysicalDeviceFeatures2);
+ this->setupDevice(mExtensions, mPhysicalDeviceFeatures2);
mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 0, &mGraphicsQueue);
- auto getProc = [] (const char* proc_name, VkInstance instance, VkDevice device) {
- if (device != VK_NULL_HANDLE) {
- return vkGetDeviceProcAddr(device, proc_name);
- }
- return vkGetInstanceProcAddr(instance, proc_name);
- };
-
- GrVkBackendContext backendContext;
- backendContext.fInstance = mInstance;
- backendContext.fPhysicalDevice = mPhysicalDevice;
- backendContext.fDevice = mDevice;
- backendContext.fQueue = mGraphicsQueue;
- backendContext.fGraphicsQueueIndex = mGraphicsQueueIndex;
- backendContext.fMaxAPIVersion = mAPIVersion;
- backendContext.fVkExtensions = &extensions;
- backendContext.fDeviceFeatures2 = &mPhysicalDeviceFeatures2;
- backendContext.fGetProc = std::move(getProc);
-
// create the command pool for the command buffers
if (VK_NULL_HANDLE == mCommandPool) {
VkCommandPoolCreateInfo commandPoolInfo;
@@ -376,22 +353,35 @@ void VulkanManager::initialize() {
}
LOG_ALWAYS_FATAL_IF(mDummyCB == VK_NULL_HANDLE);
-
mGetDeviceQueue(mDevice, mPresentQueueIndex, 0, &mPresentQueue);
- GrContextOptions options;
- options.fDisableDistanceFieldPaths = true;
- // TODO: get a string describing the SPIR-V compiler version and use it here
- mRenderThread.cacheManager().configureContext(&options, nullptr, 0);
- sk_sp<GrContext> grContext(GrContext::MakeVulkan(backendContext, options));
- LOG_ALWAYS_FATAL_IF(!grContext.get());
- mRenderThread.setGrContext(grContext);
-
if (Properties::enablePartialUpdates && Properties::useBufferAge) {
mSwapBehavior = SwapBehavior::BufferAge;
}
}
+sk_sp<GrContext> VulkanManager::createContext(GrContextOptions options) {
+ auto getProc = [] (const char* proc_name, VkInstance instance, VkDevice device) {
+ if (device != VK_NULL_HANDLE) {
+ return vkGetDeviceProcAddr(device, proc_name);
+ }
+ return vkGetInstanceProcAddr(instance, proc_name);
+ };
+
+ GrVkBackendContext backendContext;
+ backendContext.fInstance = mInstance;
+ backendContext.fPhysicalDevice = mPhysicalDevice;
+ backendContext.fDevice = mDevice;
+ backendContext.fQueue = mGraphicsQueue;
+ backendContext.fGraphicsQueueIndex = mGraphicsQueueIndex;
+ backendContext.fMaxAPIVersion = mAPIVersion;
+ backendContext.fVkExtensions = &mExtensions;
+ backendContext.fDeviceFeatures2 = &mPhysicalDeviceFeatures2;
+ backendContext.fGetProc = std::move(getProc);
+
+ return GrContext::MakeVulkan(backendContext, options);
+}
+
VkFunctorInitParams VulkanManager::getVkFunctorInitParams() const {
return VkFunctorInitParams{
.instance = mInstance,
@@ -470,8 +460,9 @@ SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface** surfaceOut) {
ColorMode colorMode = surface->mColorMode;
sk_sp<SkColorSpace> colorSpace = surface->mColorSpace;
SkColorType colorType = surface->mColorType;
+ GrContext* grContext = surface->mGrContext;
destroySurface(surface);
- *surfaceOut = createSurface(window, colorMode, colorSpace, colorType);
+ *surfaceOut = createSurface(window, colorMode, colorSpace, colorType, grContext);
surface = *surfaceOut;
if (!surface) {
return nullptr;
@@ -650,7 +641,7 @@ void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExt
VulkanSurface::ImageInfo& imageInfo = surface->mImageInfos[i];
imageInfo.mSurface = SkSurface::MakeFromBackendRenderTarget(
- mRenderThread.getGrContext(), backendRT, kTopLeft_GrSurfaceOrigin,
+ surface->mGrContext, backendRT, kTopLeft_GrSurfaceOrigin,
surface->mColorType, surface->mColorSpace, &props);
}
@@ -880,15 +871,15 @@ bool VulkanManager::createSwapchain(VulkanSurface* surface) {
VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode colorMode,
sk_sp<SkColorSpace> surfaceColorSpace,
- SkColorType surfaceColorType) {
- initialize();
-
+ SkColorType surfaceColorType,
+ GrContext* grContext) {
+ LOG_ALWAYS_FATAL_IF(!hasVkContext(), "Not initialized");
if (!window) {
return nullptr;
}
VulkanSurface* surface = new VulkanSurface(colorMode, window, surfaceColorSpace,
- surfaceColorType);
+ surfaceColorType, grContext);
VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo;
memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR));
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 1fe6c65b35b8..97636865a629 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -22,6 +22,8 @@
#endif
#include <vulkan/vulkan.h>
+#include <GrContextOptions.h>
+#include <vk/GrVkExtensions.h>
#include <SkSurface.h>
#include <ui/Fence.h>
#include <utils/StrongPointer.h>
@@ -39,9 +41,9 @@ class RenderThread;
class VulkanSurface {
public:
VulkanSurface(ColorMode colorMode, ANativeWindow* window, sk_sp<SkColorSpace> colorSpace,
- SkColorType colorType)
+ SkColorType colorType, GrContext* grContext)
: mColorMode(colorMode), mNativeWindow(window), mColorSpace(colorSpace),
- mColorType(colorType) {}
+ mColorType(colorType), mGrContext(grContext) {}
sk_sp<SkSurface> getBackBufferSurface() { return mBackbuffer; }
@@ -93,6 +95,7 @@ private:
SkColorType mColorType;
VkSurfaceTransformFlagBitsKHR mTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
SkMatrix mPreTransform;
+ GrContext* mGrContext;
};
// This class contains the shared global Vulkan objects, such as VkInstance, VkDevice and VkQueue,
@@ -100,6 +103,9 @@ private:
// windowing contexts. The VulkanManager must be initialized before use.
class VulkanManager {
public:
+ explicit VulkanManager() {}
+ ~VulkanManager() { destroy(); }
+
// Sets up the vulkan context that is shared amonst all clients of the VulkanManager. This must
// be call once before use of the VulkanManager. Multiple calls after the first will simiply
// return.
@@ -112,7 +118,8 @@ public:
// VulkanSurface object which is returned.
VulkanSurface* createSurface(ANativeWindow* window, ColorMode colorMode,
sk_sp<SkColorSpace> surfaceColorSpace,
- SkColorType surfaceColorType);
+ SkColorType surfaceColorType,
+ GrContext* grContext);
// Destroy the VulkanSurface and all associated vulkan objects.
void destroySurface(VulkanSurface* surface);
@@ -143,12 +150,9 @@ public:
// Returned pointers are owned by VulkanManager.
VkFunctorInitParams getVkFunctorInitParams() const;
-private:
- friend class RenderThread;
-
- explicit VulkanManager(RenderThread& thread);
- ~VulkanManager() { destroy(); }
+ sk_sp<GrContext> createContext(GrContextOptions options);
+private:
// Sets up the VkInstance and VkDevice objects. Also fills out the passed in
// VkPhysicalDeviceFeatures struct.
void setupDevice(GrVkExtensions&, VkPhysicalDeviceFeatures2&);
@@ -231,8 +235,6 @@ private:
VkPtr<PFN_vkWaitForFences> mWaitForFences;
VkPtr<PFN_vkResetFences> mResetFences;
- RenderThread& mRenderThread;
-
VkInstance mInstance = VK_NULL_HANDLE;
VkPhysicalDevice mPhysicalDevice = VK_NULL_HANDLE;
VkDevice mDevice = VK_NULL_HANDLE;
@@ -256,6 +258,7 @@ private:
BufferAge,
};
SwapBehavior mSwapBehavior = SwapBehavior::Discard;
+ GrVkExtensions mExtensions;
};
} /* namespace renderthread */
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index a9f651d38a06..e8ba15fe92af 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -100,7 +100,7 @@ void TestUtils::TestTask::run() {
// RenderState only valid once RenderThread is running, so queried here
renderthread::RenderThread& renderThread = renderthread::RenderThread::getInstance();
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
- renderThread.vulkanManager().initialize();
+ renderThread.requireVkContext();
} else {
renderThread.requireGlContext();
}
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index d742cc34b57e..733b866d9c4c 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -115,10 +115,14 @@ PointerController::~PointerController() {
mLocked.pointerSprite.clear();
- for (size_t i = 0; i < mLocked.spots.size(); i++) {
- delete mLocked.spots.itemAt(i);
+ for (auto& it : mLocked.spotsByDisplay) {
+ const std::vector<Spot*>& spots = it.second;
+ size_t numSpots = spots.size();
+ for (size_t i = 0; i < numSpots; i++) {
+ delete spots[i];
+ }
}
- mLocked.spots.clear();
+ mLocked.spotsByDisplay.clear();
mLocked.recycledSprites.clear();
}
@@ -271,22 +275,30 @@ void PointerController::setPresentation(Presentation presentation) {
}
void PointerController::setSpots(const PointerCoords* spotCoords,
- const uint32_t* spotIdToIndex, BitSet32 spotIdBits) {
+ const uint32_t* spotIdToIndex, BitSet32 spotIdBits, int32_t displayId) {
#if DEBUG_POINTER_UPDATES
ALOGD("setSpots: idBits=%08x", spotIdBits.value);
for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) {
uint32_t id = idBits.firstMarkedBit();
idBits.clearBit(id);
const PointerCoords& c = spotCoords[spotIdToIndex[id]];
- ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f", id,
+ ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f, displayId=%" PRId32 ".", id,
c.getAxisValue(AMOTION_EVENT_AXIS_X),
c.getAxisValue(AMOTION_EVENT_AXIS_Y),
- c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
+ c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
+ displayId);
}
#endif
AutoMutex _l(mLock);
+ std::vector<Spot*> newSpots;
+ std::map<int32_t, std::vector<Spot*>>::const_iterator iter =
+ mLocked.spotsByDisplay.find(displayId);
+ if (iter != mLocked.spotsByDisplay.end()) {
+ newSpots = iter->second;
+ }
+
mSpriteController->openTransaction();
// Add or move spots for fingers that are down.
@@ -298,17 +310,17 @@ void PointerController::setSpots(const PointerCoords* spotCoords,
float x = c.getAxisValue(AMOTION_EVENT_AXIS_X);
float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y);
- Spot* spot = getSpotLocked(id);
+ Spot* spot = getSpot(id, newSpots);
if (!spot) {
- spot = createAndAddSpotLocked(id);
+ spot = createAndAddSpotLocked(id, newSpots);
}
- spot->updateSprite(&icon, x, y);
+ spot->updateSprite(&icon, x, y, displayId);
}
// Remove spots for fingers that went up.
- for (size_t i = 0; i < mLocked.spots.size(); i++) {
- Spot* spot = mLocked.spots.itemAt(i);
+ for (size_t i = 0; i < newSpots.size(); i++) {
+ Spot* spot = newSpots[i];
if (spot->id != Spot::INVALID_ID
&& !spotIdBits.hasBit(spot->id)) {
fadeOutAndReleaseSpotLocked(spot);
@@ -316,6 +328,7 @@ void PointerController::setSpots(const PointerCoords* spotCoords,
}
mSpriteController->closeTransaction();
+ mLocked.spotsByDisplay[displayId] = newSpots;
}
void PointerController::clearSpots() {
@@ -539,21 +552,33 @@ bool PointerController::doFadingAnimationLocked(nsecs_t timestamp) {
}
// Animate spots that are fading out and being removed.
- for (size_t i = 0; i < mLocked.spots.size();) {
- Spot* spot = mLocked.spots.itemAt(i);
- if (spot->id == Spot::INVALID_ID) {
- spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION;
- if (spot->alpha <= 0) {
- mLocked.spots.removeAt(i);
- releaseSpotLocked(spot);
- continue;
- } else {
- spot->sprite->setAlpha(spot->alpha);
- keepAnimating = true;
+ for(auto it = mLocked.spotsByDisplay.begin(); it != mLocked.spotsByDisplay.end();) {
+ std::vector<Spot*>& spots = it->second;
+ size_t numSpots = spots.size();
+ for (size_t i = 0; i < numSpots;) {
+ Spot* spot = spots[i];
+ if (spot->id == Spot::INVALID_ID) {
+ spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION;
+ if (spot->alpha <= 0) {
+ spots.erase(spots.begin() + i);
+ releaseSpotLocked(spot);
+ numSpots--;
+ continue;
+ } else {
+ spot->sprite->setAlpha(spot->alpha);
+ keepAnimating = true;
+ }
}
+ ++i;
+ }
+
+ if (spots.size() == 0) {
+ it = mLocked.spotsByDisplay.erase(it);
+ } else {
+ ++it;
}
- ++i;
}
+
return keepAnimating;
}
@@ -655,47 +680,49 @@ void PointerController::updatePointerLocked() REQUIRES(mLock) {
mSpriteController->closeTransaction();
}
-PointerController::Spot* PointerController::getSpotLocked(uint32_t id) {
- for (size_t i = 0; i < mLocked.spots.size(); i++) {
- Spot* spot = mLocked.spots.itemAt(i);
+PointerController::Spot* PointerController::getSpot(uint32_t id, const std::vector<Spot*>& spots) {
+ for (size_t i = 0; i < spots.size(); i++) {
+ Spot* spot = spots[i];
if (spot->id == id) {
return spot;
}
}
- return NULL;
+
+ return nullptr;
}
-PointerController::Spot* PointerController::createAndAddSpotLocked(uint32_t id) {
+PointerController::Spot* PointerController::createAndAddSpotLocked(uint32_t id,
+ std::vector<Spot*>& spots) {
// Remove spots until we have fewer than MAX_SPOTS remaining.
- while (mLocked.spots.size() >= MAX_SPOTS) {
- Spot* spot = removeFirstFadingSpotLocked();
+ while (spots.size() >= MAX_SPOTS) {
+ Spot* spot = removeFirstFadingSpotLocked(spots);
if (!spot) {
- spot = mLocked.spots.itemAt(0);
- mLocked.spots.removeAt(0);
+ spot = spots[0];
+ spots.erase(spots.begin());
}
releaseSpotLocked(spot);
}
// Obtain a sprite from the recycled pool.
sp<Sprite> sprite;
- if (! mLocked.recycledSprites.isEmpty()) {
- sprite = mLocked.recycledSprites.top();
- mLocked.recycledSprites.pop();
+ if (! mLocked.recycledSprites.empty()) {
+ sprite = mLocked.recycledSprites.back();
+ mLocked.recycledSprites.pop_back();
} else {
sprite = mSpriteController->createSprite();
}
// Return the new spot.
Spot* spot = new Spot(id, sprite);
- mLocked.spots.push(spot);
+ spots.push_back(spot);
return spot;
}
-PointerController::Spot* PointerController::removeFirstFadingSpotLocked() {
- for (size_t i = 0; i < mLocked.spots.size(); i++) {
- Spot* spot = mLocked.spots.itemAt(i);
+PointerController::Spot* PointerController::removeFirstFadingSpotLocked(std::vector<Spot*>& spots) {
+ for (size_t i = 0; i < spots.size(); i++) {
+ Spot* spot = spots[i];
if (spot->id == Spot::INVALID_ID) {
- mLocked.spots.removeAt(i);
+ spots.erase(spots.begin() + i);
return spot;
}
}
@@ -706,7 +733,7 @@ void PointerController::releaseSpotLocked(Spot* spot) {
spot->sprite->clearIcon();
if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) {
- mLocked.recycledSprites.push(spot->sprite);
+ mLocked.recycledSprites.push_back(spot->sprite);
}
delete spot;
@@ -720,9 +747,13 @@ void PointerController::fadeOutAndReleaseSpotLocked(Spot* spot) {
}
void PointerController::fadeOutAndReleaseAllSpotsLocked() {
- for (size_t i = 0; i < mLocked.spots.size(); i++) {
- Spot* spot = mLocked.spots.itemAt(i);
- fadeOutAndReleaseSpotLocked(spot);
+ for (auto& it : mLocked.spotsByDisplay) {
+ const std::vector<Spot*>& spots = it.second;
+ size_t numSpots = spots.size();
+ for (size_t i = 0; i < numSpots; i++) {
+ Spot* spot = spots[i];
+ fadeOutAndReleaseSpotLocked(spot);
+ }
}
}
@@ -743,12 +774,13 @@ void PointerController::loadResourcesLocked() REQUIRES(mLock) {
// --- PointerController::Spot ---
-void PointerController::Spot::updateSprite(const SpriteIcon* icon, float x, float y) {
+void PointerController::Spot::updateSprite(const SpriteIcon* icon, float x, float y,
+ int32_t displayId) {
sprite->setLayer(Sprite::BASE_LAYER_SPOT + id);
sprite->setAlpha(alpha);
sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale));
sprite->setPosition(x, y);
-
+ sprite->setDisplayId(displayId);
this->x = x;
this->y = y;
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index be057867890d..52305b8244a6 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -103,7 +103,7 @@ public:
virtual void setPresentation(Presentation presentation);
virtual void setSpots(const PointerCoords* spotCoords,
- const uint32_t* spotIdToIndex, BitSet32 spotIdBits);
+ const uint32_t* spotIdToIndex, BitSet32 spotIdBits, int32_t displayId);
virtual void clearSpots();
void updatePointerIcon(int32_t iconId);
@@ -133,7 +133,7 @@ private:
: id(id), sprite(sprite), alpha(1.0f), scale(1.0f),
x(0.0f), y(0.0f), lastIcon(NULL) { }
- void updateSprite(const SpriteIcon* icon, float x, float y);
+ void updateSprite(const SpriteIcon* icon, float x, float y, int32_t displayId);
private:
const SpriteIcon* lastIcon;
@@ -180,8 +180,8 @@ private:
int32_t buttonState;
- Vector<Spot*> spots;
- Vector<sp<Sprite> > recycledSprites;
+ std::map<int32_t /* displayId */, std::vector<Spot*>> spotsByDisplay;
+ std::vector<sp<Sprite> > recycledSprites;
} mLocked GUARDED_BY(mLock);
bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
@@ -200,9 +200,9 @@ private:
void removeInactivityTimeoutLocked();
void updatePointerLocked();
- Spot* getSpotLocked(uint32_t id);
- Spot* createAndAddSpotLocked(uint32_t id);
- Spot* removeFirstFadingSpotLocked();
+ Spot* getSpot(uint32_t id, const std::vector<Spot*>& spots);
+ Spot* createAndAddSpotLocked(uint32_t id, std::vector<Spot*>& spots);
+ Spot* removeFirstFadingSpotLocked(std::vector<Spot*>& spots);
void releaseSpotLocked(Spot* spot);
void fadeOutAndReleaseSpotLocked(Spot* spot);
void fadeOutAndReleaseAllSpotsLocked();
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index 59eff6401deb..a545f2edd1bf 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -96,7 +96,7 @@ public final class GnssMeasurement implements Parcelable {
STATE_TOW_DECODED, STATE_MSEC_AMBIGUOUS, STATE_SYMBOL_SYNC, STATE_GLO_STRING_SYNC,
STATE_GLO_TOD_DECODED, STATE_BDS_D2_BIT_SYNC, STATE_BDS_D2_SUBFRAME_SYNC,
STATE_GAL_E1BC_CODE_LOCK, STATE_GAL_E1C_2ND_CODE_LOCK, STATE_GAL_E1B_PAGE_SYNC,
- STATE_SBAS_SYNC, STATE_TOW_KNOWN, STATE_GLO_TOD_KNOWN
+ STATE_SBAS_SYNC, STATE_TOW_KNOWN, STATE_GLO_TOD_KNOWN, STATE_2ND_CODE_LOCK
})
@Retention(RetentionPolicy.SOURCE)
public @interface State {}
@@ -144,6 +144,9 @@ public final class GnssMeasurement implements Parcelable {
*/
public static final int STATE_GLO_TOD_KNOWN = (1<<15);
+ /** This GNSS measurement's tracking state has secondary code lock. */
+ public static final int STATE_2ND_CODE_LOCK = (1 << 16);
+
/**
* All the GNSS receiver state flags, for bit masking purposes (not a sensible state for any
* individual measurement.)
@@ -517,6 +520,9 @@ public final class GnssMeasurement implements Parcelable {
if ((mState & STATE_SBAS_SYNC) != 0) {
builder.append("SbasSync|");
}
+ if ((mState & STATE_2ND_CODE_LOCK) != 0) {
+ builder.append("2ndCodeLock|");
+ }
int remainingStates = mState & ~STATE_ALL;
if (remainingStates > 0) {
@@ -531,96 +537,315 @@ public final class GnssMeasurement implements Parcelable {
/**
* Gets the received GNSS satellite time, at the measurement time, in nanoseconds.
*
- * <p>For GPS &amp; QZSS, this is:
- * <ul>
- * <li>Received GPS Time-of-Week at the measurement time, in nanoseconds.</li>
- * <li>The value is relative to the beginning of the current GPS week.</li>
- * </ul>
- *
- * <p>Given the highest sync state that can be achieved, per each satellite, valid range
- * for this field can be:
- * <pre>
- * Searching : [ 0 ] : STATE_UNKNOWN
- * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK is set
- * Bit sync : [ 0 20ms ] : STATE_BIT_SYNC is set
- * Subframe sync : [ 0 6s ] : STATE_SUBFRAME_SYNC is set
- * TOW decoded : [ 0 1week ] : STATE_TOW_DECODED is set
- * TOW Known : [ 0 1week ] : STATE_TOW_KNOWN set</pre>
- *
- * Note: TOW Known refers to the case where TOW is possibly not decoded over the air but has
+ * <p>The received satellite time is relative to the beginning of the system week for all
+ * constellations except for Glonass where it is relative to the beginning of the Glonass
+ * system day.
+ *
+ * <p>The table below indicates the valid range of the received GNSS satellite time. These
+ * ranges depend on the constellation and code being tracked and the state of the tracking
+ * algorithms given by the {@link #getState} method. The minimum value of this field is zero.
+ * The maximum value of this field is determined by looking across all of the state flags
+ * that are set, for the given constellation and code type, and finding the the maximum value
+ * in this table.
+ *
+ * <p>For example, for GPS L1 C/A, if STATE_TOW_KNOWN is set, this field can be any value from 0
+ * to 1 week (in nanoseconds), and for GAL E1B code, if only STATE_GAL_E1BC_CODE_LOCK is set,
+ * then this field can be any value from 0 to 4 milliseconds (in nanoseconds.)
+ *
+ * <table border="1">
+ * <thead>
+ * <tr>
+ * <td />
+ * <td colspan="3"><strong>GPS/QZSS</strong></td>
+ * <td><strong>GLNS</strong></td>
+ * <td colspan="2"><strong>BDS</strong></td>
+ * <td colspan="3"><strong>GAL</strong></td>
+ * <td><strong>SBAS</strong></td>
+ * </tr>
+ * <tr>
+ * <td><strong>State Flag</strong></td>
+ * <td><strong>L1 C/A</strong></td>
+ * <td><strong>L5I</strong></td>
+ * <td><strong>L5Q</strong></td>
+ * <td><strong>L1OF</strong></td>
+ * <td><strong>B1I (D1)</strong></td>
+ * <td><strong>B1I &nbsp;(D2)</strong></td>
+ * <td><strong>E1B</strong></td>
+ * <td><strong>E1C</strong></td>
+ * <td><strong>E5AQ</strong></td>
+ * <td><strong>L1 C/A</strong></td>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td>
+ * <strong>STATE_UNKNOWN</strong>
+ * </td>
+ * <td>0</td>
+ * <td>0</td>
+ * <td>0</td>
+ * <td>0</td>
+ * <td>0</td>
+ * <td>0</td>
+ * <td>0</td>
+ * <td>0</td>
+ * <td>0</td>
+ * <td>0</td>
+ * </tr>
+ * <tr>
+ * <td>
+ * <strong>STATE_CODE_LOCK</strong>
+ * </td>
+ * <td>1 ms</td>
+ * <td>1 ms</td>
+ * <td>1 ms</td>
+ * <td>1 ms</td>
+ * <td>1 ms</td>
+ * <td>1 ms</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>1 ms</td>
+ * <td>1 ms</td>
+ * </tr>
+ * <tr>
+ * <td>
+ * <strong>STATE_SYMBOL_SYNC</strong>
+ * </td>
+ * <td>20 ms (optional)</td>
+ * <td>10 ms</td>
+ * <td>1 ms (optional)</td>
+ * <td>10 ms</td>
+ * <td>20 ms (optional)</td>
+ * <td>2 ms</td>
+ * <td>4 ms (optional)</td>
+ * <td>4 ms (optional)</td>
+ * <td>1 ms (optional)</td>
+ * <td>2 ms</td>
+ * </tr>
+ * <tr>
+ * <td>
+ * <strong>STATE_BIT_SYNC</strong>
+ * </td>
+ * <td>20 ms</td>
+ * <td>20 ms</td>
+ * <td>1 ms (optional)</td>
+ * <td>20 ms</td>
+ * <td>20 ms</td>
+ * <td>-</td>
+ * <td>8 ms</td>
+ * <td>-</td>
+ * <td>1 ms (optional)</td>
+ * <td>4 ms</td>
+ * </tr>
+ * <tr>
+ * <td>
+ * <strong>STATE_SUBFRAME_SYNC</strong>
+ * </td>
+ * <td>6s</td>
+ * <td>6s</td>
+ * <td>-</td>
+ * <td>2 s</td>
+ * <td>6 s</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>100 ms</td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>
+ * <strong>STATE_TOW_DECODED</strong>
+ * </td>
+ * <td colspan="2">1 week</td>
+ * <td>-</td>
+ * <td>1 day</td>
+ * <td colspan="2">1 week</td>
+ * <td colspan="2">1 week</td>
+ * <td>-</td>
+ * <td>1 week</td>
+ * </tr>
+ * <tr>
+ * <td>
+ * <strong>STATE_TOW_KNOWN</strong>
+ * </td>
+ * <td colspan="3">1 week</td>
+ * <td>1 day</td>
+ * <td colspan="2">1 week</td>
+ * <td colspan="3">1 week</td>
+ * <td>1 week</td>
+ * </tr>
+ * <tr>
+ * <td>
+ * <strong>STATE_GLO_STRING_SYNC</strong>
+ * </td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>2 s</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>
+ * <strong>STATE_GLO_TOD_DECODED</strong>
+ * </td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>1 day</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>
+ * <strong>STATE_GLO_TOD_KNOWN</strong>
+ * </td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>1 day</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>
+ * <strong>STATE_BDS_D2_BIT_SYNC</strong>
+ * </td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>2 ms</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>
+ * <strong>STATE_BDS_D2_SUBFRAME_SYNC</strong>
+ * </td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>600 ms</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>
+ * <strong>STATE_GAL_E1BC_CODE_LOCK</strong>
+ * </td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>4 ms</td>
+ * <td>4 ms</td>
+ * <td>-</td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>
+ * <strong>STATE_GAL_E1C_2ND_CODE_LOCK</strong>
+ * </td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>100 ms</td>
+ * <td>-</td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>
+ * <strong>STATE_2ND_CODE_LOCK</strong>
+ * </td>
+ * <td>-</td>
+ * <td>10 ms (optional)</td>
+ * <td>20 ms</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>100 ms (optional)</td>
+ * <td>100 ms</td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>
+ * <strong>STATE_GAL_E1B_PAGE_SYNC</strong>
+ * </td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>2 s</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>
+ * <strong>STATE_SBAS_SYNC</strong>
+ * </td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>1 s</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ *
+ * <p>Note: TOW Known refers to the case where TOW is possibly not decoded over the air but has
* been determined from other sources. If TOW decoded is set then TOW Known must also be set.
*
- * <p>Note well: if there is any ambiguity in integer millisecond, {@code STATE_MSEC_AMBIGUOUS}
- * must be set accordingly, in the 'state' field.
- *
- * <p>This value must be populated if 'state' != {@code STATE_UNKNOWN}.
+ * <p>Note well: if there is any ambiguity in integer millisecond, STATE_MSEC_AMBIGUOUS must be
+ * set accordingly, in the 'state' field. This value must be populated, unless the 'state' ==
+ * STATE_UNKNOWN.
*
- * <p>For Glonass, this is:
+ * <p>Note on optional flags:
* <ul>
- * <li>Received Glonass time of day, at the measurement time in nanoseconds.</li>
+ * <li> For L1 C/A and B1I, STATE_SYMBOL_SYNC is optional since the symbol length is the
+ * same as the bit length.
+ * <li> For L5Q and E5aQ, STATE_BIT_SYNC and STATE_SYMBOL_SYNC are optional since they are
+ * implied by STATE_CODE_LOCK.
+ * <li> STATE_2ND_CODE_LOCK for L5I is optional since it is implied by STATE_SYMBOL_SYNC.
+ * <li> STATE_2ND_CODE_LOCK for E1C is optional since it is implied by
+ * STATE_GAL_E1C_2ND_CODE_LOCK.
+ * <li> For E1B and E1C, STATE_SYMBOL_SYNC is optional, because it is implied by
+ * STATE_GAL_E1BC_CODE_LOCK.
* </ul>
- *
- * <p>Given the highest sync state that can be achieved, per each satellite, valid range for
- * this field can be:
- * <pre>
- * Searching : [ 0 ] : STATE_UNKNOWN
- * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK is set
- * Symbol sync : [ 0 10ms ] : STATE_SYMBOL_SYNC is set
- * Bit sync : [ 0 20ms ] : STATE_BIT_SYNC is set
- * String sync : [ 0 2s ] : STATE_GLO_STRING_SYNC is set
- * Time of day decoded : [ 0 1day ] : STATE_GLO_TOD_DECODED is set
- * Time of day known : [ 0 1day ] : STATE_GLO_TOD_KNOWN set</pre>
- *
- * Note: Time of day known refers to the case where it is possibly not decoded over the air but
- * has been determined from other sources. If Time of day decoded is set then Time of day known
- * must also be set.
- *
- * <p>For Beidou, this is:
- * <ul>
- * <li>Received Beidou time of week, at the measurement time in nanoseconds.</li>
- * </ul>
- *
- * <p>Given the highest sync state that can be achieved, per each satellite, valid range for
- * this field can be:
- * <pre>
- * Searching : [ 0 ] : STATE_UNKNOWN
- * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK is set
- * Bit sync (D2) : [ 0 2ms ] : STATE_BDS_D2_BIT_SYNC is set
- * Bit sync (D1) : [ 0 20ms ] : STATE_BIT_SYNC is set
- * Subframe (D2) : [ 0 0.6s ] : STATE_BDS_D2_SUBFRAME_SYNC is set
- * Subframe (D1) : [ 0 6s ] : STATE_SUBFRAME_SYNC is set
- * Time of week decoded : [ 0 1week ] : STATE_TOW_DECODED is set
- * Time of week known : [ 0 1week ] : STATE_TOW_KNOWN set</pre>
- *
- * Note: TOW Known refers to the case where TOW is possibly not decoded over the air but has
- * been determined from other sources. If TOW decoded is set then TOW Known must also be set.
- *
- * <p>For Galileo, this is:
- * <ul>
- * <li>Received Galileo time of week, at the measurement time in nanoseconds.</li>
- * </ul>
- * <pre>
- * E1BC code lock : [ 0 4ms ] : STATE_GAL_E1BC_CODE_LOCK is set
- * E1C 2nd code lock : [ 0 100ms ] : STATE_GAL_E1C_2ND_CODE_LOCK is set
- * E1B page : [ 0 2s ] : STATE_GAL_E1B_PAGE_SYNC is set
- * Time of week decoded : [ 0 1week ] : STATE_TOW_DECODED is set
- * Time of week known : [ 0 1week ] : STATE_TOW_KNOWN set</pre>
- *
- * Note: TOW Known refers to the case where TOW is possibly not decoded over the air but has
- * been determined from other sources. If TOW decoded is set then TOW Known must also be set.
- *
- * <p>For SBAS, this is:
- * <ul>
- * <li>Received SBAS time, at the measurement time in nanoseconds.</li>
- * </ul>
- *
- * <p>Given the highest sync state that can be achieved, per each satellite, valid range for
- * this field can be:
- * <pre>
- * Searching : [ 0 ] : STATE_UNKNOWN
- * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK is set
- * Symbol sync : [ 0 2ms ] : STATE_SYMBOL_SYNC is set
- * Message : [ 0 1s ] : STATE_SBAS_SYNC is set</pre>
*/
public long getReceivedSvTimeNanos() {
return mReceivedSvTimeNanos;
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index 0caa0c5b377a..b3953fddb622 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -184,8 +184,7 @@ public final class LocationRequest implements Parcelable {
* @return a new location request
*/
public static LocationRequest create() {
- LocationRequest request = new LocationRequest();
- return request;
+ return new LocationRequest();
}
/** @hide */
@@ -230,12 +229,10 @@ public final class LocationRequest implements Parcelable {
quality = ACCURACY_FINE;
break;
default: {
- switch (criteria.getPowerRequirement()) {
- case Criteria.POWER_HIGH:
- quality = POWER_HIGH;
- break;
- default:
- quality = POWER_LOW;
+ if (criteria.getPowerRequirement() == Criteria.POWER_HIGH) {
+ quality = POWER_HIGH;
+ } else {
+ quality = POWER_LOW;
}
}
}
@@ -288,7 +285,7 @@ public final class LocationRequest implements Parcelable {
*
* @param quality an accuracy or power constant
* @return the same object, so that setters can be chained
- * @throws InvalidArgumentException if the quality constant is not valid
+ * @throws IllegalArgumentException if the quality constant is not valid
*/
public LocationRequest setQuality(int quality) {
checkQuality(quality);
@@ -331,7 +328,7 @@ public final class LocationRequest implements Parcelable {
*
* @param millis desired interval in millisecond, inexact
* @return the same object, so that setters can be chained
- * @throws InvalidArgumentException if the interval is less than zero
+ * @throws IllegalArgumentException if the interval is less than zero
*/
public LocationRequest setInterval(long millis) {
checkInterval(millis);
@@ -433,7 +430,7 @@ public final class LocationRequest implements Parcelable {
*
* @param millis fastest interval for updates in milliseconds, exact
* @return the same object, so that setters can be chained
- * @throws InvalidArgumentException if the interval is less than zero
+ * @throws IllegalArgumentException if the interval is less than zero
*/
public LocationRequest setFastestInterval(long millis) {
checkInterval(millis);
@@ -528,7 +525,7 @@ public final class LocationRequest implements Parcelable {
*
* @param numUpdates the number of location updates requested
* @return the same object, so that setters can be chained
- * @throws InvalidArgumentException if numUpdates is 0 or less
+ * @throws IllegalArgumentException if numUpdates is 0 or less
*/
public LocationRequest setNumUpdates(int numUpdates) {
if (numUpdates <= 0) {
@@ -668,7 +665,7 @@ public final class LocationRequest implements Parcelable {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static void checkProvider(String name) {
if (name == null) {
- throw new IllegalArgumentException("invalid provider: " + name);
+ throw new IllegalArgumentException("invalid provider: null");
}
}
@@ -758,9 +755,11 @@ public final class LocationRequest implements Parcelable {
if (mNumUpdates != Integer.MAX_VALUE) {
s.append(" num=").append(mNumUpdates);
}
- s.append(" lowPowerMode=").append(mLowPowerMode);
+ if (mLowPowerMode) {
+ s.append(" lowPowerMode");
+ }
if (mLocationSettingsIgnored) {
- s.append(" ignoreSettings");
+ s.append(" locationSettingsIgnored");
}
s.append(']');
return s.toString();
diff --git a/location/java/com/android/internal/location/ProviderRequest.java b/location/java/com/android/internal/location/ProviderRequest.java
index a45c20d9d09d..af8123ac52f4 100644
--- a/location/java/com/android/internal/location/ProviderRequest.java
+++ b/location/java/com/android/internal/location/ProviderRequest.java
@@ -40,7 +40,7 @@ public final class ProviderRequest implements Parcelable {
* restrictions or any other restricting factors and always satisfy this request to the best of
* their ability. This flag should only be used in event of an emergency.
*/
- public boolean forceLocation = false;
+ public boolean locationSettingsIgnored = false;
/**
* Whether provider shall make stronger than normal tradeoffs to substantially restrict power
@@ -70,6 +70,7 @@ public final class ProviderRequest implements Parcelable {
request.reportLocation = in.readInt() == 1;
request.interval = in.readLong();
request.lowPowerMode = in.readBoolean();
+ request.locationSettingsIgnored = in.readBoolean();
int count = in.readInt();
for (int i = 0; i < count; i++) {
request.locationRequests.add(LocationRequest.CREATOR.createFromParcel(in));
@@ -93,6 +94,7 @@ public final class ProviderRequest implements Parcelable {
parcel.writeInt(reportLocation ? 1 : 0);
parcel.writeLong(interval);
parcel.writeBoolean(lowPowerMode);
+ parcel.writeBoolean(locationSettingsIgnored);
parcel.writeInt(locationRequests.size());
for (LocationRequest request : locationRequests) {
request.writeToParcel(parcel, flags);
@@ -107,7 +109,12 @@ public final class ProviderRequest implements Parcelable {
s.append("ON");
s.append(" interval=");
TimeUtils.formatDuration(interval, s);
- s.append(" lowPowerMode=" + lowPowerMode);
+ if (lowPowerMode) {
+ s.append(" lowPowerMode");
+ }
+ if (locationSettingsIgnored) {
+ s.append(" locationSettingsIgnored");
+ }
} else {
s.append("OFF");
}
diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt
index 67d64965ac96..dbb581fe54b2 100644
--- a/location/lib/api/current.txt
+++ b/location/lib/api/current.txt
@@ -31,6 +31,7 @@ package com.android.location.provider {
method public long getInterval();
method public int getQuality();
method public float getSmallestDisplacement();
+ method public boolean isLocationSettingsIgnored();
field public static final int ACCURACY_BLOCK = 102; // 0x66
field public static final int ACCURACY_CITY = 104; // 0x68
field public static final int ACCURACY_FINE = 100; // 0x64
@@ -44,10 +45,10 @@ package com.android.location.provider {
}
public final class ProviderRequestUnbundled {
- method public boolean getForceLocation();
method public long getInterval();
method public java.util.List<com.android.location.provider.LocationRequestUnbundled> getLocationRequests();
method public boolean getReportLocation();
+ method public boolean isLocationSettingsIgnored();
}
}
diff --git a/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java b/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java
index 41fd769b5abd..2511c39caf5c 100644
--- a/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java
+++ b/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java
@@ -121,6 +121,15 @@ public final class LocationRequestUnbundled {
return delegate.getSmallestDisplacement();
}
+ /**
+ * Returns true if location settings will be ignored in order to satisfy this request.
+ *
+ * @return true if location settings will be ignored in order to satisfy this request
+ */
+ public boolean isLocationSettingsIgnored() {
+ return delegate.isLocationSettingsIgnored();
+ }
+
@Override
public String toString() {
return delegate.toString();
diff --git a/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java b/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
index b825b58cd3e9..febbf1b23e0c 100644
--- a/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
+++ b/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
@@ -46,15 +46,15 @@ public final class ProviderRequestUnbundled {
return mRequest.interval;
}
- public boolean getForceLocation() {
- return mRequest.forceLocation;
+ public boolean isLocationSettingsIgnored() {
+ return mRequest.locationSettingsIgnored;
}
/**
* Never null.
*/
public List<LocationRequestUnbundled> getLocationRequests() {
- List<LocationRequestUnbundled> result = new ArrayList<LocationRequestUnbundled>(
+ List<LocationRequestUnbundled> result = new ArrayList<>(
mRequest.locationRequests.size());
for (LocationRequest r : mRequest.locationRequests) {
result.add(new LocationRequestUnbundled(r));
diff --git a/media/Android.bp b/media/Android.bp
index 141d415cbaf3..86dc509501a4 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -3,7 +3,6 @@ java_library {
srcs: [
":updatable-media-srcs",
- ":framework-media-annotation-srcs",
],
aidl: {
@@ -28,7 +27,12 @@ java_library {
installable: true,
// Make sure that the implementaion only relies on SDK or system APIs.
- sdk_version: "system_current",
+ no_framework_libs: true,
+ libs: [
+ // The order matters. android_system_* library should come later.
+ "framework_media_annotation",
+ "android_system_stubs_current",
+ ],
}
filegroup {
@@ -125,3 +129,8 @@ java_library {
sdk_version: "28",
}
+java_library {
+ name: "framework_media_annotation",
+ srcs: [":framework-media-annotation-srcs"],
+ installable: false,
+}
diff --git a/media/apex/java/android/media/MediaController2.java b/media/apex/java/android/media/MediaController2.java
index 887b4475a4d1..e85d99774986 100644
--- a/media/apex/java/android/media/MediaController2.java
+++ b/media/apex/java/android/media/MediaController2.java
@@ -425,7 +425,7 @@ public class MediaController2 implements AutoCloseable {
public void onDisconnected(@NonNull MediaController2 controller) {}
/**
- * Called when the playback of the session's playback activeness is changed.
+ * Called when the session's playback activeness is changed.
*
* @param controller the controller for this event
* @param playbackActive {@code true} if the session's playback is active.
diff --git a/media/apex/java/android/media/MediaPlayer2.java b/media/apex/java/android/media/MediaPlayer2.java
index c38a83131a6c..89a954061958 100644
--- a/media/apex/java/android/media/MediaPlayer2.java
+++ b/media/apex/java/android/media/MediaPlayer2.java
@@ -45,8 +45,8 @@ import android.util.Size;
import android.view.Surface;
import android.view.SurfaceHolder;
-import com.android.framework.protobuf.InvalidProtocolBufferException;
import com.android.internal.annotations.GuardedBy;
+import com.android.media.protobuf.InvalidProtocolBufferException;
import java.io.ByteArrayOutputStream;
import java.io.File;
diff --git a/media/java/android/media/IRingtonePlayer.aidl b/media/java/android/media/IRingtonePlayer.aidl
index 5f6686a88a7e..c038f36206f6 100644
--- a/media/java/android/media/IRingtonePlayer.aidl
+++ b/media/java/android/media/IRingtonePlayer.aidl
@@ -17,6 +17,7 @@
package android.media;
import android.media.AudioAttributes;
+import android.media.VolumeShaper;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
@@ -27,6 +28,8 @@ import android.os.UserHandle;
interface IRingtonePlayer {
/** Used for Ringtone.java playback */
oneway void play(IBinder token, in Uri uri, in AudioAttributes aa, float volume, boolean looping);
+ oneway void playWithVolumeShaping(IBinder token, in Uri uri, in AudioAttributes aa,
+ float volume, boolean looping, in @nullable VolumeShaper.Configuration volumeShaperConfig);
oneway void stop(IBinder token);
boolean isPlaying(IBinder token);
oneway void setPlaybackProperties(IBinder token, float volume, boolean looping);
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 572c5f4b3e67..4bc3897c4477 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -1614,29 +1614,59 @@ public final class MediaCodecInfo {
}
/**
- * Video performance points are a set of standard performance points defined by pixel rate.
+ * Video performance points are a set of standard performance points defined by number of
+ * pixels, pixel rate and frame rate. Performance point represents an upper bound. This
+ * means that it covers all performance points with fewer pixels, pixel rate and frame
+ * rate.
*/
public static final class PerformancePoint {
/**
- * Frame width in pixels.
+ * (Maximum) number of macroblocks in the frame.
+ *
+ * Video frames are conceptually divided into 16-by-16 pixel blocks called macroblocks.
+ * Most coding standards operate on these 16-by-16 pixel blocks; thus, codec performance
+ * is characterized using such blocks.
*/
- public final int width;
+ public final int macroBlocks;
/**
- * Frame height in pixels.
+ * (Maximum) frame rate in frames per second.
*/
- public final int height;
+ public final int frameRate;
/**
- * Frame rate in frames per second.
+ * (Maximum) number of macroblocks processed per second.
*/
- public final int frameRate;
+ public final long macroBlockRate;
/* package private */
- PerformancePoint(int width_, int height_, int frameRate_) {
- width = width_;
- height = height_;
- frameRate = frameRate_;
+ PerformancePoint(int width_, int height_, int frameRate_, int maxFrameRate_) {
+ macroBlocks = saturateLongToInt(
+ ((Math.max(1, (long)width_) + 15) / 16)
+ * ((Math.max(1, (long)height_) + 15) / 16));
+ frameRate = Math.max(1, frameRate_);
+ macroBlockRate = Math.max(maxFrameRate_, frameRate) * macroBlocks;
+ }
+
+ /**
+ * Create a performance point for a given frame size and frame rate.
+ *
+ * @param width_ width of the frame in pixels
+ * @param height_ height of the frame in pixels
+ * @param frameRate_ frame rate in frames per second
+ */
+ public PerformancePoint(int width_, int height_, int frameRate_) {
+ this(width_, height_, frameRate_, frameRate_ /* maxFrameRate */);
+ }
+
+ private int saturateLongToInt(long value) {
+ if (value < Integer.MIN_VALUE) {
+ return Integer.MIN_VALUE;
+ } else if (value > Integer.MAX_VALUE) {
+ return Integer.MAX_VALUE;
+ } else {
+ return (int)value;
+ }
}
/**
@@ -1647,26 +1677,40 @@ public final class MediaCodecInfo {
* @return {@code true} if the performance point covers the format.
*/
public boolean covers(@NonNull MediaFormat format) {
- // for simplicity, this code assumes a 16x16 block size.
- long macroBlocks = ((width + 15) / 16) * (long)((height + 15) / 16);
- long mbps = macroBlocks * frameRate;
+ PerformancePoint other = new PerformancePoint(
+ format.getInteger(MediaFormat.KEY_WIDTH, 0),
+ format.getInteger(MediaFormat.KEY_HEIGHT, 0),
+ // safely convert ceil(double) to int through float case and Math.round
+ Math.round((float)(
+ Math.ceil(format.getNumber(MediaFormat.KEY_FRAME_RATE, 0)
+ .doubleValue()))));
+ return covers(other);
+ }
- long formatMacroBlocks =
- (long)((format.getInteger(MediaFormat.KEY_WIDTH, 0) + 15) / 16)
- * ((format.getInteger(MediaFormat.KEY_HEIGHT, 0) + 15) / 16);
- double formatMbps =
- Math.ceil(formatMacroBlocks
- * format.getNumber(MediaFormat.KEY_FRAME_RATE, 0).doubleValue());
- return formatMacroBlocks > 0 && formatMacroBlocks <= macroBlocks
- && formatMbps <= mbps;
+ /**
+ * Checks whether the performance point covers another performance point. Use this
+ * method to determine if a performance point advertised by a codec covers the
+ * performance point required. This method can also be used for lose ordering as this
+ * method is transitive.
+ *
+ * @param other other performance point considered
+ *
+ * @return {@code true} if the performance point covers the other.
+ */
+ public boolean covers(@NonNull PerformancePoint other) {
+ return (macroBlocks >= other.macroBlocks
+ && frameRate >= other.frameRate
+ && macroBlockRate >= other.macroBlockRate);
}
+
@Override
public boolean equals(Object o) {
if (o instanceof PerformancePoint) {
PerformancePoint other = (PerformancePoint)o;
- return ((long)width * height) == ((long)other.width * other.height)
- && frameRate == other.frameRate;
+ return (macroBlocks == other.macroBlocks
+ && frameRate == other.frameRate
+ && macroBlockRate == other.macroBlockRate);
}
return false;
}
@@ -1931,7 +1975,8 @@ public final class MediaCodecInfo {
continue;
}
ret.add(new PerformancePoint(
- size.getWidth(), size.getHeight(), range.getLower().intValue()));
+ size.getWidth(), size.getHeight(), range.getLower().intValue(),
+ range.getUpper().intValue()));
}
// check if the component specified no performance point indication
if (ret.size() == 0) {
@@ -1939,9 +1984,12 @@ public final class MediaCodecInfo {
}
// sort reversed by area first, then by frame rate
- ret.sort((a, b) -> (a.width * a.height != b.width * b.height ?
- (b.width * b.height - a.width * a.height) :
- (b.frameRate - a.frameRate)));
+ ret.sort((a, b) -> -((a.macroBlocks != b.macroBlocks) ?
+ (a.macroBlocks < b.macroBlocks ? -1 : 1) :
+ (a.macroBlockRate != b.macroBlockRate) ?
+ (a.macroBlockRate < b.macroBlockRate ? -1 : 1) :
+ (a.frameRate != b.frameRate) ?
+ (a.frameRate < b.frameRate ? -1 : 1) : 0));
return ret;
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index fb18c3b67480..e4d356b48f6d 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1180,13 +1180,8 @@ public class MediaPlayer extends PlayerBase
}
final File file = new File(path);
- if (file.exists()) {
- FileInputStream is = new FileInputStream(file);
- FileDescriptor fd = is.getFD();
- setDataSource(fd);
- is.close();
- } else {
- throw new IOException("setDataSource failed.");
+ try (FileInputStream is = new FileInputStream(file)) {
+ setDataSource(is.getFD());
}
}
@@ -2868,15 +2863,9 @@ public class MediaPlayer extends PlayerBase
throw new IllegalArgumentException(msg);
}
- File file = new File(path);
- if (file.exists()) {
- FileInputStream is = new FileInputStream(file);
- FileDescriptor fd = is.getFD();
- addTimedTextSource(fd, mimeType);
- is.close();
- } else {
- // We do not support the case where the path is not a file.
- throw new IOException(path);
+ final File file = new File(path);
+ try (FileInputStream is = new FileInputStream(file)) {
+ addTimedTextSource(is.getFD(), mimeType);
}
}
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 73d3d889e464..eb680c8377f4 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -381,7 +381,8 @@ public class Ringtone {
volume = mVolume;
}
try {
- mRemotePlayer.play(mRemoteToken, canonicalUri, mAudioAttributes, volume, looping);
+ mRemotePlayer.playWithVolumeShaping(mRemoteToken, canonicalUri, mAudioAttributes,
+ volume, looping, mVolumeShaperConfig);
} catch (RemoteException e) {
if (!playFallbackRingtone()) {
Log.w(TAG, "Problem playing ringtone: " + e);
diff --git a/core/java/android/os/ParcelFileDescriptor.aidl b/media/java/android/media/VolumeShaper.aidl
index c07b98055d5a..e99c13f8a6f3 100644
--- a/core/java/android/os/ParcelFileDescriptor.aidl
+++ b/media/java/android/media/VolumeShaper.aidl
@@ -1,20 +1,19 @@
-/* //device/java/android/android/os/ParcelFileDescriptor.aidl
+/* Copyright 2019, The Android Open Source Project
**
-** Copyright 2007, 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
**
-** 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
**
-** 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
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
-package android.os;
+package android.media;
-parcelable ParcelFileDescriptor cpp_header "binder/ParcelFileDescriptor.h";
+parcelable VolumeShaper;
+parcelable VolumeShaper.Configuration;
diff --git a/media/java/android/media/session/ControllerLink.java b/media/java/android/media/session/ControllerLink.java
index 64d283f168e1..40c716607697 100644
--- a/media/java/android/media/session/ControllerLink.java
+++ b/media/java/android/media/session/ControllerLink.java
@@ -493,6 +493,22 @@ public final class ControllerLink implements Parcelable {
}
/**
+ * Tell system that a controller requests changing the playback speed.
+ *
+ * @param packageName the package name of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ * @param speed the playback speed
+ */
+ void setPlaybackSpeed(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
+ float speed) {
+ try {
+ mISessionController.setPlaybackSpeed(packageName, caller, speed);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
* Tell system that a controller sends a custom action.
*
* @param packageName the package name of the controller
@@ -759,6 +775,11 @@ public final class ControllerLink implements Parcelable {
@NonNull Rating rating) {
}
+ /** Stub method for ISessionController.setPlaybackSpeed */
+ public void setPlaybackSpeed(@NonNull String packageName,
+ @NonNull ControllerCallbackLink caller, float speed) {
+ }
+
/** Stub method for ISessionController.sendCustomAction */
public void sendCustomAction(@NonNull String packageName,
@NonNull ControllerCallbackLink caller, @NonNull String action,
@@ -953,6 +974,12 @@ public final class ControllerLink implements Parcelable {
}
@Override
+ public void setPlaybackSpeed(String packageName, ControllerCallbackLink caller,
+ float speed) {
+ mControllerStub.setPlaybackSpeed(packageName, caller, speed);
+ }
+
+ @Override
public void sendCustomAction(String packageName, ControllerCallbackLink caller,
String action, Bundle args) {
mControllerStub.sendCustomAction(packageName, caller, action, args);
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index 9b86bfced340..cd33c044d142 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -60,6 +60,8 @@ oneway interface ISessionCallback {
long pos);
void notifyRate(String packageName, int pid, int uid, in ControllerCallbackLink caller,
in Rating rating);
+ void notifySetPlaybackSpeed(String packageName, int pid, int uid,
+ in ControllerCallbackLink caller, float speed);
void notifyCustomAction(String packageName, int pid, int uid, in ControllerCallbackLink caller,
String action, in Bundle args);
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index e697c65e11c0..3e7b4fbdebd3 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -76,6 +76,7 @@ interface ISessionController {
void rewind(String packageName, in ControllerCallbackLink caller);
void seekTo(String packageName, in ControllerCallbackLink caller, long pos);
void rate(String packageName, in ControllerCallbackLink caller, in Rating rating);
+ void setPlaybackSpeed(String packageName, in ControllerCallbackLink caller, float speed);
void sendCustomAction(String packageName, in ControllerCallbackLink caller,
String action, in Bundle args);
MediaMetadata getMetadata();
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 6e2c8c51c734..9e4199cba47a 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -865,6 +865,19 @@ public final class MediaController {
}
/**
+ * Set the playback speed.
+ *
+ * @param speed The playback speed
+ */
+ public void setPlaybackSpeed(float speed) {
+ try {
+ mSessionBinder.setPlaybackSpeed(mContext.getPackageName(), mCbStub, speed);
+ } catch (RuntimeException e) {
+ Log.wtf(TAG, "Error calling setPlaybackSpeed.", e);
+ }
+ }
+
+ /**
* Send a custom action back for the {@link MediaSession} to perform.
*
* @param customAction The action to perform.
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 1b9ebdafd328..8ab893b03a62 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -681,6 +681,19 @@ public final class MediaSession {
}
/**
+ * Override to handle the playback speed change.
+ * To update the new playback speed, create a new {@link PlaybackState} by using {@link
+ * PlaybackState.Builder#setState(int, long, float)}, and set it with
+ * {@link #setPlaybackState(PlaybackState)}.
+ *
+ * @param speed the playback speed
+ * @see #setPlaybackState(PlaybackState)
+ * @see PlaybackState.Builder#setState(int, long, float)
+ */
+ public void onSetPlaybackSpeed(float speed) {
+ }
+
+ /**
* Called when a {@link MediaController} wants a {@link PlaybackState.CustomAction} to be
* performed.
*
diff --git a/media/java/android/media/session/MediaSessionEngine.java b/media/java/android/media/session/MediaSessionEngine.java
index e19bdbcf923e..266bf3226c49 100644
--- a/media/java/android/media/session/MediaSessionEngine.java
+++ b/media/java/android/media/session/MediaSessionEngine.java
@@ -538,6 +538,10 @@ public final class MediaSessionEngine implements AutoCloseable {
postToCallback(caller, CallbackMessageHandler.MSG_RATE, rating, null);
}
+ void dispatchSetPlaybackSpeed(RemoteUserInfo caller, float speed) {
+ postToCallback(caller, CallbackMessageHandler.MSG_SET_PLAYBACK_SPEED, speed, null);
+ }
+
void dispatchCustomAction(RemoteUserInfo caller, String action, Bundle args) {
postToCallback(caller, CallbackMessageHandler.MSG_CUSTOM_ACTION, action, args);
}
@@ -871,6 +875,17 @@ public final class MediaSessionEngine implements AutoCloseable {
}
/**
+ * Override to handle the playback speed change.
+ *
+ * @param speed the playback speed
+ */
+ public void onSetPlaybackSpeed(float speed) {
+ if (mCallback != null) {
+ mCallback.onSetPlaybackSpeed(speed);
+ }
+ }
+
+ /**
* Called when a {@link MediaController} wants a {@link PlaybackState.CustomAction} to be
* performed.
*
@@ -1092,10 +1107,11 @@ public final class MediaSessionEngine implements AutoCloseable {
private static final int MSG_REWIND = 17;
private static final int MSG_SEEK_TO = 18;
private static final int MSG_RATE = 19;
- private static final int MSG_CUSTOM_ACTION = 20;
- private static final int MSG_ADJUST_VOLUME = 21;
- private static final int MSG_SET_VOLUME = 22;
- private static final int MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT = 23;
+ private static final int MSG_SET_PLAYBACK_SPEED = 20;
+ private static final int MSG_CUSTOM_ACTION = 21;
+ private static final int MSG_ADJUST_VOLUME = 22;
+ private static final int MSG_SET_VOLUME = 23;
+ private static final int MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT = 24;
@SuppressWarnings("WeakerAccess") /* synthetic access */
CallbackWrapper mCallbackWrapper;
@@ -1186,6 +1202,9 @@ public final class MediaSessionEngine implements AutoCloseable {
case MSG_RATE:
mCallbackWrapper.onSetRating((Rating) obj);
break;
+ case MSG_SET_PLAYBACK_SPEED:
+ mCallbackWrapper.onSetPlaybackSpeed((Float) obj);
+ break;
case MSG_CUSTOM_ACTION:
mCallbackWrapper.onCustomAction((String) obj, msg.getData());
break;
diff --git a/media/java/android/media/session/SessionCallbackLink.java b/media/java/android/media/session/SessionCallbackLink.java
index f59a69d6e157..f9fa45a1b619 100644
--- a/media/java/android/media/session/SessionCallbackLink.java
+++ b/media/java/android/media/session/SessionCallbackLink.java
@@ -462,6 +462,25 @@ public final class SessionCallbackLink implements Parcelable {
}
/**
+ * Notify session that a controller requests changing playback speed.
+ *
+ * @param packageName the package name of the controller
+ * @param pid the pid of the controller
+ * @param uid the uid of the controller
+ * @param caller the {@link ControllerCallbackLink} of the controller
+ * @param speed the playback speed
+ */
+ @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+ public void notifySetPlaybackSpeed(@NonNull String packageName, int pid, int uid,
+ @NonNull ControllerCallbackLink caller, float speed) {
+ try {
+ mISessionCallback.notifySetPlaybackSpeed(packageName, pid, uid, caller, speed);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
* Notify session that a controller sends a custom action.
*
* @param packageName the package name of the controller
@@ -871,6 +890,23 @@ public final class SessionCallbackLink implements Parcelable {
}
}
+ @Override
+ public void notifySetPlaybackSpeed(String packageName, int pid, int uid,
+ ControllerCallbackLink caller, float speed) {
+ ensureMediaControlPermission();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ MediaSessionEngine sessionImpl = mSessionImpl.get();
+ if (sessionImpl != null) {
+ sessionImpl.dispatchSetPlaybackSpeed(
+ createRemoteUserInfo(packageName, pid, uid), speed);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
public void notifyCustomAction(String packageName, int pid, int uid,
ControllerCallbackLink caller, String action, Bundle args) {
ensureMediaControlPermission();
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index e08dab48ce39..49066950a9fb 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -17,8 +17,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "SoundPool"
+#include <chrono>
#include <inttypes.h>
-
+#include <thread>
#include <utils/Log.h>
#define USE_SHARED_MEM_BUFFER
@@ -967,6 +968,12 @@ bool SoundChannel::doStop_l()
if (mState != IDLE) {
setVolume_l(0, 0);
ALOGV("stop");
+ // Since we're forcibly halting the previously playing content,
+ // we sleep here to ensure the volume is ramped down before we stop the track.
+ // Ideally the sleep time is the mixer period, or an approximation thereof
+ // (Fast vs Normal tracks are different).
+ // TODO: consider pausing instead of stop here.
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
mAudioTrack->stop();
mPrevSampleID = mSample->sampleID();
mSample.clear();
diff --git a/media/native/midi/Android.bp b/media/native/midi/Android.bp
index d069bd2f6284..58317edbea68 100644
--- a/media/native/midi/Android.bp
+++ b/media/native/midi/Android.bp
@@ -16,7 +16,7 @@ cc_library_shared {
name: "libamidi",
srcs: [
- "midi.cpp",
+ "amidi.cpp",
":IMidiDeviceServer.aidl",
],
@@ -48,10 +48,10 @@ ndk_headers {
from: "include",
- to: "amidi",
+ to: "",
- srcs: ["include/midi.h"],
- license: "include/NOTICE",
+ srcs: ["include/amidi/AMidi.h"],
+ license: "include/amidi/NOTICE",
}
ndk_library {
diff --git a/media/native/midi/midi.cpp b/media/native/midi/amidi.cpp
index a5bdba8569b8..1e9a194d76c8 100644
--- a/media/native/midi/midi.cpp
+++ b/media/native/midi/amidi.cpp
@@ -28,8 +28,8 @@
#include "android/media/midi/BpMidiDeviceServer.h"
#include "media/MidiDeviceInfo.h"
-#include "include/midi.h"
-#include "midi_internal.h"
+#include "include/amidi/AMidi.h"
+#include "amidi_internal.h"
using namespace android::media::midi;
diff --git a/media/native/midi/midi_internal.h b/media/native/midi/amidi_internal.h
index cb3ecce13533..fce85963d217 100644
--- a/media/native/midi/midi_internal.h
+++ b/media/native/midi/amidi_internal.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_MEDIA_MIDI_INTERNAL_H_
-#define ANDROID_MEDIA_MIDI_INTERNAL_H_
+#ifndef ANDROID_MEDIA_AMIDI_INTERNAL_H_
+#define ANDROID_MEDIA_AMIDI_INTERNAL_H_
#include <jni.h>
@@ -38,4 +38,4 @@ struct AMidiDevice {
AMidiDeviceInfo deviceInfo; /* Attributes of the device. */
};
-#endif // ANDROID_MEDIA_MIDI_INTERNAL_H_
+#endif // ANDROID_MEDIA_AMIDI_INTERNAL_H_
diff --git a/media/native/midi/include/midi.h b/media/native/midi/include/amidi/AMidi.h
index 755d09fc4ff2..0d60b0dd63d4 100644
--- a/media/native/midi/include/midi.h
+++ b/media/native/midi/include/amidi/AMidi.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_MEDIA_MIDI_H_
-#define ANDROID_MEDIA_MIDI_H_
+#ifndef ANDROID_MEDIA_AMIDI_H_
+#define ANDROID_MEDIA_AMIDI_H_
#include <stdarg.h>
#include <stdint.h>
@@ -66,9 +66,9 @@ enum {
* @param outDevicePtrPtr Points to the pointer to receive the AMidiDevice
*
* @return AMEDIA_OK on success, or a negative error value:
- * @see AMEDIA_ERROR_INVALID_OBJECT {@link AMEDIA_ERROR_INVALID_OBJECT} - the midiDeviceObj
+ * @see AMEDIA_ERROR_INVALID_OBJECT - the midiDeviceObj
* is null or already connected to a native AMidiDevice
- * @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - an unknown error occurred.
+ * @see AMEDIA_ERROR_UNKNOWN - an unknown error occurred.
*/
media_status_t AMIDI_API AMidiDevice_fromJava(
JNIEnv *env, jobject midiDeviceObj, AMidiDevice **outDevicePtrPtr) __INTRODUCED_IN(29);
@@ -80,13 +80,10 @@ media_status_t AMIDI_API AMidiDevice_fromJava(
*
* @return AMEDIA_OK on success,
* or a negative error value:
- * @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER}
- * - the device parameter is NULL.
- * @see AMEDIA_ERROR_INVALID_OBJECT {@link AMEDIA_ERROR_INVALID_OBJECT}
- * - the device is not consistent with the associated Java MidiDevice.
- * @see AMEDIA_ERROR_INVALID_OBJECT {@link AMEDIA_ERROR_INVALID_OBJECT}
- * - the JNI interface initialization to the associated java MidiDevice failed.
- * @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - couldn't retrieve the device info.
+ * @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
+ * @see AMEDIA_ERROR_INVALID_OBJECT - the device is not consistent with the associated Java MidiDevice.
+ * @see AMEDIA_ERROR_INVALID_OBJECT - the JNI interface initialization to the associated java MidiDevice failed.
+ * @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info.
*/
media_status_t AMIDI_API AMidiDevice_release(const AMidiDevice *midiDevice) __INTRODUCED_IN(29);
@@ -100,9 +97,8 @@ media_status_t AMIDI_API AMidiDevice_release(const AMidiDevice *midiDevice) __IN
* AMIDI_DEVICE_TYPE_VIRTUAL
* AMIDI_DEVICE_TYPE_BLUETOOTH
* or a negative error value:
- * @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER} - the device
- * parameter is NULL.
- * @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - Unknown error.
+ * @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
+ * @see AMEDIA_ERROR_UNKNOWN - Unknown error.
*/
int32_t AMIDI_API AMidiDevice_getType(const AMidiDevice *device) __INTRODUCED_IN(29);
@@ -113,9 +109,8 @@ int32_t AMIDI_API AMidiDevice_getType(const AMidiDevice *device) __INTRODUCED_IN
*
* @return If successful, returns the number of MIDI input (sending) ports available on the
* device. If an error occurs, returns a negative value indicating the error:
- * @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER} - the device
- * parameter is NULL.
- * @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - couldn't retrieve the device info.
+ * @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
+ * @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info.
*/
ssize_t AMIDI_API AMidiDevice_getNumInputPorts(const AMidiDevice *device) __INTRODUCED_IN(29);
@@ -126,9 +121,8 @@ ssize_t AMIDI_API AMidiDevice_getNumInputPorts(const AMidiDevice *device) __INTR
*
* @return If successful, returns the number of MIDI output (receiving) ports available on the
* device. If an error occurs, returns a negative value indicating the error:
- * @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER} - the device
- * parameter is NULL.
- * @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN}- couldn't retrieve the device info.
+ * @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
+ * @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info.
*/
ssize_t AMIDI_API AMidiDevice_getNumOutputPorts(const AMidiDevice *device) __INTRODUCED_IN(29);
@@ -146,7 +140,7 @@ ssize_t AMIDI_API AMidiDevice_getNumOutputPorts(const AMidiDevice *device) __INT
* @param outOutputPortPtr Receives the native API port identifier of the opened port.
*
* @return AMEDIA_OK, or a negative error code:
- * @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - Unknown Error.
+ * @see AMEDIA_ERROR_UNKNOWN - Unknown Error.
*/
media_status_t AMIDI_API AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber,
AMidiOutputPort **outOutputPortPtr) __INTRODUCED_IN(29);
@@ -174,7 +168,7 @@ void AMIDI_API AMidiOutputPort_close(const AMidiOutputPort *outputPort) __INTROD
* (the current value of the running Java Virtual Machine's high-resolution time source,
* in nanoseconds)
* @return the number of messages received (either 0 or 1), or a negative error code:
- * @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - Unknown Error.
+ * @see AMEDIA_ERROR_UNKNOWN - Unknown Error.
*/
ssize_t AMIDI_API AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr,
uint8_t *buffer, size_t maxBytes, size_t* numBytesReceivedPtr, int64_t *outTimestampPtr) __INTRODUCED_IN(29);
@@ -193,7 +187,7 @@ ssize_t AMIDI_API AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int
* @param outInputPortPtr Receives the native API port identifier of the opened port.
*
* @return AMEDIA_OK, or a negative error code:
- * @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - Unknown Error.
+ * @see AMEDIA_ERROR_UNKNOWN - Unknown Error.
*/
media_status_t AMIDI_API AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber,
AMidiInputPort **outInputPortPtr) __INTRODUCED_IN(29);
@@ -206,8 +200,7 @@ media_status_t AMIDI_API AMidiInputPort_open(const AMidiDevice *device, int32_t
* @param numBytes Specifies the number of bytes to write.
*
* @return The number of bytes sent, which could be less than specified or a negative error code:
- * @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER} The specified port
- * was NULL, the specified buffer was NULL.
+ * @see AMEDIA_ERROR_INVALID_PARAMETER - The specified port was NULL, the specified buffer was NULL.
*/
ssize_t AMIDI_API AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer,
size_t numBytes) __INTRODUCED_IN(29);
@@ -221,8 +214,7 @@ ssize_t AMIDI_API AMidiInputPort_send(const AMidiInputPort *inputPort, const uin
* @param timestamp The CLOCK_MONOTONIC time in nanoseconds to associate with the sent data.
*
* @return The number of bytes sent, which could be less than specified or a negative error code:
- * @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER} The specified port
- * was NULL, the specified buffer was NULL.
+ * @see AMEDIA_ERROR_INVALID_PARAMETER - The specified port was NULL, the specified buffer was NULL.
*/
ssize_t AMIDI_API AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort,
const uint8_t *buffer, size_t numBytes, int64_t timestamp) __INTRODUCED_IN(29);
@@ -233,10 +225,9 @@ ssize_t AMIDI_API AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPo
*
* @param inputPort The identifier of the port to send the flush command to.
*
- * @returns @see AMEDIA_OK {@link AMEDIA_OK} if successful, otherwise a negative error code:
- * @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER} The specified port
- * was NULL
- * @see AMEDIA_ERROR_UNSUPPORTED {@link AMEDIA_ERROR_UNSUPPORTED} The FLUSH command couldn't
+ * @returns @see AMEDIA_OK if successful, otherwise a negative error code:
+ * @see AMEDIA_ERROR_INVALID_PARAMETER - The specified port was NULL
+ * @see AMEDIA_ERROR_UNSUPPORTED - The FLUSH command couldn't
* be sent.
*/
media_status_t AMIDI_API AMidiInputPort_sendFlush(const AMidiInputPort *inputPort) __INTRODUCED_IN(29);
@@ -252,4 +243,4 @@ void AMIDI_API AMidiInputPort_close(const AMidiInputPort *inputPort) __INTRODUCE
}
#endif
-#endif /* ANDROID_MEDIA_MIDI_H_ */
+#endif /* ANDROID_MEDIA_AMIDI_H_ */
diff --git a/media/native/midi/include/NOTICE b/media/native/midi/include/amidi/NOTICE
index e72ff94a8401..e72ff94a8401 100644
--- a/media/native/midi/include/NOTICE
+++ b/media/native/midi/include/amidi/NOTICE
diff --git a/media/packages/MediaCore/Android.bp.bak b/media/packages/MediaCore/Android.bp.bak
deleted file mode 100644
index c7fd58bf933a..000000000000
--- a/media/packages/MediaCore/Android.bp.bak
+++ /dev/null
@@ -1,21 +0,0 @@
-android_app {
- name: "MediaCore",
-
- srcs: [
- "src/**/*.java",
- ],
-
- static_libs: [
- // TODO: Temporarily statically linked. Should go into "libs"
- "media1",
- ],
-
- // System app
- platform_apis: true,
-
- // Privileged app
- privileged: true,
-
- // Make sure that the implementation only relies on SDK or system APIs.
- sdk_version: "system_current",
-}
diff --git a/media/packages/MediaCore/AndroidManifest.xml b/media/packages/MediaCore/AndroidManifest.xml
deleted file mode 100644
index 4e2b274511e8..000000000000
--- a/media/packages/MediaCore/AndroidManifest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/AndroidManifest.xml
-**
-** Copyright 2019, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.media" coreApp="true" android:sharedUserId="android.uid.system"
- android:sharedUserLabel="@string/android_system_label">
- <application android:process="system"
- android:persistent="true"
- android:directBootAware="true">
- <service android:name="AmlMediaSessionProviderService" android:singleUser="true">
- <intent-filter>
- <action android:name="android.media.session.MediaSessionProviderService"/>
- </intent-filter>
- </service>
- </application>
-</manifest>
diff --git a/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java b/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java
deleted file mode 100644
index 43b95ab7ebdb..000000000000
--- a/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.media;
-
-import android.content.Context;
-import android.media.session.MediaSessionProviderService;
-import android.os.PowerManager;
-import android.util.Log;
-
-/**
- * System implementation of MediaSessionProviderService
- */
-public class AmlMediaSessionProviderService extends MediaSessionProviderService {
- private static final String TAG = "AmlMediaSessionProviderS";
- static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
- private Context mContext;
-
- public AmlMediaSessionProviderService(Context context) {
- mContext = context;
- PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- }
-}
diff --git a/media/proto/jarjar-rules.txt b/media/proto/jarjar-rules.txt
index 7be6e732d3fd..bfb0b2782486 100644
--- a/media/proto/jarjar-rules.txt
+++ b/media/proto/jarjar-rules.txt
@@ -1,2 +1,2 @@
-rule com.google.protobuf.** com.android.framework.protobuf.@1
+rule com.google.protobuf.** com.android.media.protobuf.@1
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 51afbc7d91b0..a3db2d6a5055 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -146,6 +146,7 @@ LIBANDROID {
AHardwareBuffer_getNativeHandle; # introduced=26
AHardwareBuffer_isSupported; # introduced=29
AHardwareBuffer_lock; # introduced=26
+ AHardwareBuffer_lockPlanes; # introduced=29
AHardwareBuffer_recvHandleFromUnixSocket; # introduced=26
AHardwareBuffer_release; # introduced=26
AHardwareBuffer_sendHandleToUnixSocket; # introduced=26
@@ -230,6 +231,7 @@ LIBANDROID {
ASurfaceTransaction_reparent; # introduced=29
ASurfaceTransaction_setBuffer; # introduced=29
ASurfaceTransaction_setBufferAlpha; # introduced=29
+ ASurfaceTransaction_setBufferDataSpace; # introduced=29
ASurfaceTransaction_setBufferTransparency; # introduced=29
ASurfaceTransaction_setColor; # introduced=29
ASurfaceTransaction_setDamageRegion; # introduced=29
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 7d2934b8554e..d07052bb3b3f 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -440,6 +440,20 @@ void ASurfaceTransaction_setBufferAlpha(ASurfaceTransaction* aSurfaceTransaction
transaction->setAlpha(surfaceControl, alpha);
}
+void ASurfaceTransaction_setBufferDataSpace(ASurfaceTransaction* aSurfaceTransaction,
+ ASurfaceControl* aSurfaceControl,
+ ADataSpace aDataSpace) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+ CHECK_NOT_NULL(aSurfaceControl);
+
+ sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+ LOG_ALWAYS_FATAL_IF(!isDataSpaceValid(surfaceControl, aDataSpace), "invalid dataspace");
+
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+ transaction->setDataspace(surfaceControl, static_cast<ui::Dataspace>(aDataSpace));
+}
+
void ASurfaceTransaction_setHdrMetadata_smpte2086(ASurfaceTransaction* aSurfaceTransaction,
ASurfaceControl* aSurfaceControl,
struct AHdrMetadata_smpte2086* metadata) {
diff --git a/packages/CaptivePortalLogin/res/values-gl/strings.xml b/packages/CaptivePortalLogin/res/values-gl/strings.xml
index f6f4aea0c639..64195168f76f 100644
--- a/packages/CaptivePortalLogin/res/values-gl/strings.xml
+++ b/packages/CaptivePortalLogin/res/values-gl/strings.xml
@@ -13,7 +13,7 @@
<string name="ssl_error_mismatch" msgid="3060364165934822383">"O nome do sitio non coincide co nome que aparece no certificado."</string>
<string name="ssl_error_expired" msgid="1501588340716182495">"Este certificado caducou."</string>
<string name="ssl_error_not_yet_valid" msgid="8648649030525886924">"Este certificado aínda non é válido."</string>
- <string name="ssl_error_date_invalid" msgid="88425990680059223">"Este certificado ten unha data non-válida."</string>
+ <string name="ssl_error_date_invalid" msgid="88425990680059223">"Este certificado ten unha data non válida."</string>
<string name="ssl_error_invalid" msgid="2540546515565633432">"Este certificado non é válido."</string>
<string name="ssl_error_unknown" msgid="4405203446079465859">"Produciuse un erro descoñecido relacionado co certificado."</string>
<string name="ssl_security_warning_title" msgid="8768539813847504404">"Advertencia de seguranza"</string>
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index ce627ce47717..a288d010e59b 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -175,6 +175,7 @@ public class CaptivePortalLoginActivity extends Activity {
webSettings.setSupportZoom(true);
webSettings.setBuiltInZoomControls(true);
webSettings.setDisplayZoomControls(false);
+ webSettings.setDomStorageEnabled(true);
mWebViewClient = new MyWebViewClient();
webview.setWebViewClient(mWebViewClient);
webview.setWebChromeClient(new MyWebChromeClient());
diff --git a/packages/CarSystemUI/res/values/colors_car.xml b/packages/CarSystemUI/res/values/colors_car.xml
index 2f720f5aba65..08e16cdbe3b3 100644
--- a/packages/CarSystemUI/res/values/colors_car.xml
+++ b/packages/CarSystemUI/res/values/colors_car.xml
@@ -26,6 +26,4 @@
<color name="car_user_switcher_add_user_background_color">@color/car_dark_blue_grey_600</color>
<color name="car_user_switcher_add_user_add_sign_color">@color/car_body1_light</color>
- <!-- colors for volume dialog tint -->
- <color name="car_volume_dialog_tint">@color/car_tint</color>
</resources>
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 2dba1d5bc257..c5a951ca5249 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -221,30 +221,6 @@ public class CarStatusBar extends StatusBar implements
}
}
- @Override
- public void destroy() {
- mCarBatteryController.stopListening();
- mConnectedDeviceSignalController.stopListening();
- mActivityManagerWrapper.unregisterTaskStackListener(mTaskStackListener);
- mDrivingStateHelper.disconnectFromCarService();
-
- if (mNavigationBarWindow != null) {
- mWindowManager.removeViewImmediate(mNavigationBarWindow);
- mNavigationBarView = null;
- }
-
- if (mLeftNavigationBarWindow != null) {
- mWindowManager.removeViewImmediate(mLeftNavigationBarWindow);
- mLeftNavigationBarView = null;
- }
-
- if (mRightNavigationBarWindow != null) {
- mWindowManager.removeViewImmediate(mRightNavigationBarWindow);
- mRightNavigationBarView = null;
- }
- super.destroy();
- }
-
@Override
protected void makeStatusBarView() {
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index 85dab57b5f21..10a0ae5a924c 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -554,8 +554,7 @@ public class CarVolumeDialogImpl implements VolumeDialog {
// Adding the items which are not coming from the default item.
VolumeItem volumeItem = mAvailableVolumeItems.get(groupId);
if (volumeItem.defaultItem) {
- // Set progress here due to the progress of seekbar may not be updated.
- volumeItem.listItem.setProgress(volumeItem.progress);
+ updateDefaultVolumeItem(volumeItem.listItem);
} else {
addSeekbarListItem(volumeItem, groupId, 0, null);
}
@@ -572,8 +571,7 @@ public class CarVolumeDialogImpl implements VolumeDialog {
if (!volumeItem.defaultItem) {
itr.remove();
} else {
- // Set progress here due to the progress of seekbar may not be updated.
- seekbarListItem.setProgress(volumeItem.progress);
+ updateDefaultVolumeItem(seekbarListItem);
}
}
inAnimator = AnimatorInflater.loadAnimator(
@@ -595,6 +593,21 @@ public class CarVolumeDialogImpl implements VolumeDialog {
mPagedListAdapter.notifyDataSetChanged();
}
+ private void updateDefaultVolumeItem(SeekbarListItem seekbarListItem){
+ VolumeItem volumeItem = findVolumeItem(seekbarListItem);
+
+ // When volume dialog is expanded or collapsed the default list item is never
+ // reset. Whereas all other list items are removed when the dialog is collapsed and then
+ // added when the dialog is expanded using {@link CarVolumeDialogImpl#addSeekbarListItem}.
+ // This sets the progressbar and the tint color of icons for all items other than default
+ // if they were changed. For default list item it should be done manually here.
+ int color = mContext.getResources().getColor(R.color.car_volume_dialog_tint);
+ Drawable primaryIcon = mContext.getResources().getDrawable(volumeItem.icon);
+ primaryIcon.mutate().setTint(color);
+ volumeItem.listItem.setPrimaryActionIcon(primaryIcon);
+ volumeItem.listItem.setProgress(volumeItem.progress);
+ }
+
private final class VolumeSeekBarChangeListener implements OnSeekBarChangeListener {
private final int mVolumeGroupId;
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
index f36b4aa87636..55c9361ce6c4 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
@@ -106,6 +106,7 @@ public class CaptivePortalLoginActivity extends Activity {
webSettings.setLoadWithOverviewMode(true);
webSettings.setSupportZoom(true);
webSettings.setBuiltInZoomControls(true);
+ webSettings.setDomStorageEnabled(true);
mWebViewClient = new MyWebViewClient();
mWebView.setWebViewClient(mWebViewClient);
mWebView.setWebChromeClient(new MyWebChromeClient());
diff --git a/packages/DynamicAndroidInstallationService/Android.mk b/packages/DynamicAndroidInstallationService/Android.mk
new file mode 100644
index 000000000000..13d96ac3906e
--- /dev/null
+++ b/packages/DynamicAndroidInstallationService/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, res)
+
+LOCAL_USE_AAPT2 := true
+
+LOCAL_PACKAGE_NAME := DynamicAndroidInstallationService
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_PRIVATE_PLATFORM_APIS := true
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+
+include $(BUILD_PACKAGE)
diff --git a/packages/DynamicAndroidInstallationService/AndroidManifest.xml b/packages/DynamicAndroidInstallationService/AndroidManifest.xml
new file mode 100644
index 000000000000..1c1c72c46206
--- /dev/null
+++ b/packages/DynamicAndroidInstallationService/AndroidManifest.xml
@@ -0,0 +1,47 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.dynandroid"
+ android:sharedUserId="android.uid.system">
+
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.MANAGE_DYNAMNIC_ANDROID" />
+ <uses-permission android:name="android.permission.REBOOT" />
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+
+ <application
+ android:allowBackup="false"
+ android:label="@string/app_name">
+
+ <service
+ android:name=".DynamicAndroidInstallationService"
+ android:enabled="true"
+ android:exported="true"
+ android:permission="android.permission.MANAGE_DYNAMNIC_ANDROID"
+ android:process=":dynandroid">
+ <intent-filter>
+ <action android:name="android.content.action.NOTIFY_IF_IN_USE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </service>
+
+ <activity android:name=".VerificationActivity"
+ android:exported="true"
+ android:permission="android.permission.MANAGE_DYNAMNIC_ANDROID"
+ android:theme="@android:style/Theme.Material.Light.Dialog.NoActionBar"
+ android:process=":dynandroid">
+ <intent-filter>
+ <action android:name="android.content.action.START_INSTALL" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <receiver
+ android:name=".BootCompletedReceiver"
+ android:enabled="true"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="android.intent.action.BOOT_COMPLETED" />
+ </intent-filter>
+ </receiver>
+ </application>
+</manifest>
diff --git a/packages/DynamicAndroidInstallationService/MODULE_LICENSE_APACHE2 b/packages/DynamicAndroidInstallationService/MODULE_LICENSE_APACHE2
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/packages/DynamicAndroidInstallationService/MODULE_LICENSE_APACHE2
diff --git a/packages/DynamicAndroidInstallationService/NOTICE b/packages/DynamicAndroidInstallationService/NOTICE
new file mode 100644
index 000000000000..c5b1efa7aac7
--- /dev/null
+++ b/packages/DynamicAndroidInstallationService/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2008, The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/packages/DynamicAndroidInstallationService/res/drawable/ic_system_update_googblue_24dp.xml b/packages/DynamicAndroidInstallationService/res/drawable/ic_system_update_googblue_24dp.xml
new file mode 100644
index 000000000000..acf1567ab7fe
--- /dev/null
+++ b/packages/DynamicAndroidInstallationService/res/drawable/ic_system_update_googblue_24dp.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19L7,19L7,5h10v14zM16,13h-3L13,8h-2v5L8,13l4,4 4,-4z"
+ android:fillColor="#4285F4"/>
+</vector>
diff --git a/packages/DynamicAndroidInstallationService/res/values/strings.xml b/packages/DynamicAndroidInstallationService/res/values/strings.xml
new file mode 100644
index 000000000000..221e1d75b133
--- /dev/null
+++ b/packages/DynamicAndroidInstallationService/res/values/strings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- application name [CHAR LIMIT=32] -->
+ <string name="app_name">AndroidOnTap Installer</string>
+
+ <!-- notification channel name [CHAR LIMIT=32] -->
+ <string name="notification_channel_name">AndroidOnTap Installer</string>
+
+ <!-- password page title [CHAR LIMIT=32] -->
+ <string name="keyguard_title">AndroidOnTap Installer</string>
+
+ <!-- password page description [CHAR LIMIT=128] -->
+ <string name="keyguard_description">Please enter your password and continue to AndroidOnTap installation</string>
+
+ <!-- Displayed on notification: DynAndroid installation is completed [CHAR LIMIT=128] -->
+ <string name="notification_install_completed">Installation is completed, you can reboot into the new installed system now.</string>
+ <!-- Displayed on notification: DynAndroid installation is in progress [CHAR LIMIT=128] -->
+ <string name="notification_install_inprogress">Installation is in progress.</string>
+ <!-- Displayed on notification: DynAndroid installation is in progress [CHAR LIMIT=128] -->
+ <string name="notification_install_failed">Installation Failed.</string>
+ <!-- Displayed on notification: We are running in AndroidOnTap [CHAR LIMIT=128] -->
+ <string name="notification_dynandroid_in_use">We are running in AndroidOnTap.</string>
+
+ <!-- Action on notification: Cancel installation [CHAR LIMIT=16] -->
+ <string name="notification_action_cancel">Cancel</string>
+ <!-- Action on notification: Discard installation [CHAR LIMIT=16] -->
+ <string name="notification_action_discard">Discard</string>
+ <!-- Action on notification: Uninstall AndroidOnTap [CHAR LIMIT=16] -->
+ <string name="notification_action_uninstall">Uninstall</string>
+ <!-- Action on notification: Reboot to AndroidOnTap [CHAR LIMIT=16] -->
+ <string name="notification_action_reboot_to_dynandroid">Reboot</string>
+
+</resources>
diff --git a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/BootCompletedReceiver.java b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/BootCompletedReceiver.java
new file mode 100644
index 000000000000..dd1be897b2ea
--- /dev/null
+++ b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/BootCompletedReceiver.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dynandroid;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DynamicAndroidClient;
+import android.content.Intent;
+import android.os.UserHandle;
+import android.util.Log;
+
+
+/**
+ * A BoardcastReceiver waiting for ACTION_BOOT_COMPLETED and ask
+ * the service to display a notification if we are currently running
+ * in DynamicAndroid.
+ */
+public class BootCompletedReceiver extends BroadcastReceiver {
+
+ private static final String TAG = "BootCompletedReceiver";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+
+ Log.d(TAG, "Broadcast received: " + action);
+
+ if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
+ Intent startServiceIntent = new Intent(
+ context, DynamicAndroidInstallationService.class);
+
+ startServiceIntent.setAction(DynamicAndroidClient.ACTION_NOTIFY_IF_IN_USE);
+ context.startServiceAsUser(startServiceIntent, UserHandle.SYSTEM);
+ }
+ }
+}
diff --git a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java
new file mode 100644
index 000000000000..7755cbc9ca3b
--- /dev/null
+++ b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java
@@ -0,0 +1,483 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dynandroid;
+
+import static android.content.DynamicAndroidClient.ACTION_NOTIFY_IF_IN_USE;
+import static android.content.DynamicAndroidClient.ACTION_START_INSTALL;
+import static android.content.DynamicAndroidClient.CAUSE_ERROR_EXCEPTION;
+import static android.content.DynamicAndroidClient.CAUSE_ERROR_INVALID_URL;
+import static android.content.DynamicAndroidClient.CAUSE_ERROR_IO;
+import static android.content.DynamicAndroidClient.CAUSE_INSTALL_CANCELLED;
+import static android.content.DynamicAndroidClient.CAUSE_INSTALL_COMPLETED;
+import static android.content.DynamicAndroidClient.CAUSE_NOT_SPECIFIED;
+import static android.content.DynamicAndroidClient.STATUS_IN_PROGRESS;
+import static android.content.DynamicAndroidClient.STATUS_IN_USE;
+import static android.content.DynamicAndroidClient.STATUS_NOT_STARTED;
+import static android.content.DynamicAndroidClient.STATUS_READY;
+import static android.os.AsyncTask.Status.FINISHED;
+import static android.os.AsyncTask.Status.PENDING;
+import static android.os.AsyncTask.Status.RUNNING;
+
+import static com.android.dynandroid.InstallationAsyncTask.RESULT_ERROR_EXCEPTION;
+import static com.android.dynandroid.InstallationAsyncTask.RESULT_ERROR_INVALID_URL;
+import static com.android.dynandroid.InstallationAsyncTask.RESULT_ERROR_IO;
+import static com.android.dynandroid.InstallationAsyncTask.RESULT_OK;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Context;
+import android.content.DynamicAndroidClient;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.DynamicAndroidManager;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+/**
+ * This class is the service in charge of DynamicAndroid installation.
+ * It also posts status to notification bar and wait for user's
+ * cancel and confirm commnands.
+ */
+public class DynamicAndroidInstallationService extends Service
+ implements InstallationAsyncTask.InstallStatusListener {
+
+ private static final String TAG = "DynAndroidInstallationService";
+
+ /*
+ * Intent actions
+ */
+ private static final String ACTION_CANCEL_INSTALL =
+ "com.android.dynandroid.ACTION_CANCEL_INSTALL";
+ private static final String ACTION_REBOOT_TO_DYN_ANDROID =
+ "com.android.dynandroid.ACTION_REBOOT_TO_DYN_ANDROID";
+ private static final String ACTION_REBOOT_TO_NORMAL =
+ "com.android.dynandroid.ACTION_REBOOT_TO_NORMAL";
+
+ /*
+ * For notification
+ */
+ private static final String NOTIFICATION_CHANNEL_ID = "com.android.dynandroid";
+ private static final int NOTIFICATION_ID = 1;
+
+ /*
+ * IPC
+ */
+ /** Keeps track of all current registered clients. */
+ ArrayList<Messenger> mClients = new ArrayList<>();
+
+ /** Handler of incoming messages from clients. */
+ final Messenger mMessenger = new Messenger(new IncomingHandler(this));
+
+ static class IncomingHandler extends Handler {
+ private final WeakReference<DynamicAndroidInstallationService> mWeakService;
+
+ IncomingHandler(DynamicAndroidInstallationService service) {
+ mWeakService = new WeakReference<>(service);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ DynamicAndroidInstallationService service = mWeakService.get();
+
+ if (service != null) {
+ service.handleMessage(msg);
+ }
+ }
+ }
+
+ private DynamicAndroidManager mDynAndroid;
+ private NotificationManager mNM;
+
+ private long mSystemSize;
+ private long mInstalledSize;
+ private boolean mJustCancelledByUser;
+
+ private PendingIntent mPiCancel;
+ private PendingIntent mPiRebootToDynamicAndroid;
+ private PendingIntent mPiUninstallAndReboot;
+
+ private InstallationAsyncTask mInstallTask;
+
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ prepareNotification();
+
+ mDynAndroid = (DynamicAndroidManager) getSystemService(Context.DYNAMIC_ANDROID_SERVICE);
+ }
+
+ @Override
+ public void onDestroy() {
+ // Cancel the persistent notification.
+ mNM.cancel(NOTIFICATION_ID);
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mMessenger.getBinder();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ String action = intent.getAction();
+
+ Log.d(TAG, "onStartCommand(): action=" + action);
+
+ if (ACTION_START_INSTALL.equals(action)) {
+ executeInstallCommand(intent);
+ } else if (ACTION_CANCEL_INSTALL.equals(action)) {
+ executeCancelCommand();
+ } else if (ACTION_REBOOT_TO_DYN_ANDROID.equals(action)) {
+ executeRebootToDynAndroidCommand();
+ } else if (ACTION_REBOOT_TO_NORMAL.equals(action)) {
+ executeRebootToNormalCommand();
+ } else if (ACTION_NOTIFY_IF_IN_USE.equals(action)) {
+ executeNotifyIfInUseCommand();
+ }
+
+ return Service.START_NOT_STICKY;
+ }
+
+ @Override
+ public void onProgressUpdate(long installedSize) {
+ mInstalledSize = installedSize;
+ postStatus(STATUS_IN_PROGRESS, CAUSE_NOT_SPECIFIED);
+ }
+
+ @Override
+ public void onResult(int result) {
+ if (result == RESULT_OK) {
+ postStatus(STATUS_READY, CAUSE_INSTALL_COMPLETED);
+ return;
+ }
+
+ // if it's not successful, reset the task and stop self.
+ resetTaskAndStop();
+
+ switch (result) {
+ case RESULT_ERROR_IO:
+ postStatus(STATUS_NOT_STARTED, CAUSE_ERROR_IO);
+ break;
+
+ case RESULT_ERROR_INVALID_URL:
+ postStatus(STATUS_NOT_STARTED, CAUSE_ERROR_INVALID_URL);
+ break;
+
+ case RESULT_ERROR_EXCEPTION:
+ postStatus(STATUS_NOT_STARTED, CAUSE_ERROR_EXCEPTION);
+ break;
+ }
+ }
+
+ @Override
+ public void onCancelled() {
+ resetTaskAndStop();
+ postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED);
+ }
+
+ private void executeInstallCommand(Intent intent) {
+ if (!verifyRequest(intent)) {
+ Log.e(TAG, "Verification failed. Did you use VerificationActivity?");
+ return;
+ }
+
+ if (mInstallTask != null) {
+ Log.e(TAG, "There is already an install task running");
+ return;
+ }
+
+ if (isInDynamicAndroid()) {
+ Log.e(TAG, "We are already running in DynamicAndroid");
+ return;
+ }
+
+ String url = intent.getStringExtra(DynamicAndroidClient.KEY_SYSTEM_URL);
+ mSystemSize = intent.getLongExtra(DynamicAndroidClient.KEY_SYSTEM_SIZE, 0);
+ long userdata = intent.getLongExtra(DynamicAndroidClient.KEY_USERDATA_SIZE, 0);
+
+ mInstallTask = new InstallationAsyncTask(url, mSystemSize, userdata, mDynAndroid, this);
+ mInstallTask.execute();
+
+ // start fore ground
+ startForeground(NOTIFICATION_ID,
+ buildNotification(STATUS_IN_PROGRESS, CAUSE_NOT_SPECIFIED));
+ }
+
+ private void executeCancelCommand() {
+ if (mInstallTask == null || mInstallTask.getStatus() == PENDING) {
+ Log.e(TAG, "Cancel command triggered, but there is no task running");
+ mNM.cancel(NOTIFICATION_ID);
+
+ return;
+ }
+
+ mJustCancelledByUser = true;
+
+ if (mInstallTask.cancel(false)) {
+ // Will cleanup and post status in onCancelled()
+ Log.d(TAG, "Cancel request filed successfully");
+ } else {
+ Log.d(TAG, "Requested cancel, completed task will be discarded");
+
+ resetTaskAndStop();
+ postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED);
+ }
+
+ }
+
+ private void executeRebootToDynAndroidCommand() {
+ if (mInstallTask == null || mInstallTask.getStatus() != FINISHED) {
+ Log.e(TAG, "Trying to reboot to DynamicAndroid, but there is no complete installation");
+ return;
+ }
+
+ if (!mInstallTask.commit()) {
+ // TODO: b/123673280 better UI response
+ Log.e(TAG, "Failed to commit installation because of native runtime error.");
+ mNM.cancel(NOTIFICATION_ID);
+
+ return;
+ }
+
+ PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
+
+ if (powerManager != null) {
+ powerManager.reboot("dynandroid");
+ }
+ }
+
+ private void executeRebootToNormalCommand() {
+ mDynAndroid.remove();
+
+ PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
+
+ if (powerManager != null) {
+ powerManager.reboot(null);
+ }
+ }
+
+ private void executeNotifyIfInUseCommand() {
+ if (isInDynamicAndroid()) {
+ startForeground(NOTIFICATION_ID,
+ buildNotification(STATUS_IN_USE, CAUSE_NOT_SPECIFIED));
+ }
+ }
+
+ private void resetTaskAndStop() {
+ mInstallTask = null;
+
+ stopForeground(true);
+
+ // stop self, but this service is not destroyed yet if it's still bound
+ stopSelf();
+ }
+
+ private void prepareNotification() {
+ NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID,
+ getString(R.string.notification_channel_name),
+ NotificationManager.IMPORTANCE_LOW);
+
+ mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+
+ if (mNM != null) {
+ mNM.createNotificationChannel(chan);
+ }
+
+ Intent intentCancel = new Intent(this, DynamicAndroidInstallationService.class);
+ intentCancel.setAction(ACTION_CANCEL_INSTALL);
+ mPiCancel = PendingIntent.getService(this, 0, intentCancel, 0);
+
+ Intent intentRebootToDyn = new Intent(this, DynamicAndroidInstallationService.class);
+ intentRebootToDyn.setAction(ACTION_REBOOT_TO_DYN_ANDROID);
+ mPiRebootToDynamicAndroid = PendingIntent.getService(this, 0, intentRebootToDyn, 0);
+
+ Intent intentUninstallAndReboot = new Intent(this, DynamicAndroidInstallationService.class);
+ intentUninstallAndReboot.setAction(ACTION_REBOOT_TO_NORMAL);
+ mPiUninstallAndReboot = PendingIntent.getService(this, 0, intentUninstallAndReboot, 0);
+ }
+
+ private Notification buildNotification(int status, int cause) {
+ Notification.Builder builder = new Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
+ .setSmallIcon(R.drawable.ic_system_update_googblue_24dp)
+ .setProgress(0, 0, false);
+
+ switch (status) {
+ case STATUS_IN_PROGRESS:
+ builder.setContentText(getString(R.string.notification_install_inprogress));
+
+ int max = (int) Math.max(mSystemSize >> 20, 1);
+ int progress = (int) mInstalledSize >> 20;
+
+ builder.setProgress(max, progress, false);
+
+ builder.addAction(new Notification.Action.Builder(
+ null, getString(R.string.notification_action_cancel),
+ mPiCancel).build());
+
+ break;
+
+ case STATUS_READY:
+ builder.setContentText(getString(R.string.notification_install_completed));
+
+ builder.addAction(new Notification.Action.Builder(
+ null, getString(R.string.notification_action_reboot_to_dynandroid),
+ mPiRebootToDynamicAndroid).build());
+
+ builder.addAction(new Notification.Action.Builder(
+ null, getString(R.string.notification_action_cancel),
+ mPiCancel).build());
+
+ break;
+
+ case STATUS_IN_USE:
+ builder.setContentText(getString(R.string.notification_dynandroid_in_use));
+
+ builder.addAction(new Notification.Action.Builder(
+ null, getString(R.string.notification_action_uninstall),
+ mPiUninstallAndReboot).build());
+
+ break;
+
+ case STATUS_NOT_STARTED:
+ if (cause != CAUSE_NOT_SPECIFIED && cause != CAUSE_INSTALL_CANCELLED) {
+ builder.setContentText(getString(R.string.notification_install_failed));
+ } else {
+ // no need to notify the user if the task is not started, or cancelled.
+ }
+ break;
+
+ default:
+ throw new IllegalStateException("status is invalid");
+ }
+
+ return builder.build();
+ }
+
+ private boolean verifyRequest(Intent intent) {
+ String url = intent.getStringExtra(DynamicAndroidClient.KEY_SYSTEM_URL);
+
+ return VerificationActivity.isVerified(url);
+ }
+
+ private void postStatus(int status, int cause) {
+ Log.d(TAG, "postStatus(): statusCode=" + status + ", causeCode=" + cause);
+
+ boolean notifyOnNotificationBar = true;
+
+ if (status == STATUS_NOT_STARTED
+ && cause == CAUSE_INSTALL_CANCELLED
+ && mJustCancelledByUser) {
+ // if task is cancelled by user, do not notify them
+ notifyOnNotificationBar = false;
+ mJustCancelledByUser = false;
+ }
+
+ if (notifyOnNotificationBar) {
+ mNM.notify(NOTIFICATION_ID, buildNotification(status, cause));
+ }
+
+ for (int i = mClients.size() - 1; i >= 0; i--) {
+ try {
+ notifyOneClient(mClients.get(i), status, cause);
+ } catch (RemoteException e) {
+ mClients.remove(i);
+ }
+ }
+ }
+
+ private void notifyOneClient(Messenger client, int status, int cause) throws RemoteException {
+ Bundle bundle = new Bundle();
+
+ bundle.putLong(DynamicAndroidClient.KEY_INSTALLED_SIZE, mInstalledSize);
+
+ client.send(Message.obtain(null,
+ DynamicAndroidClient.MSG_POST_STATUS, status, cause, bundle));
+ }
+
+ private int getStatus() {
+ if (isInDynamicAndroid()) {
+ return STATUS_IN_USE;
+
+ } else if (mInstallTask == null) {
+ return STATUS_NOT_STARTED;
+
+ }
+
+ switch (mInstallTask.getStatus()) {
+ case PENDING:
+ return STATUS_NOT_STARTED;
+
+ case RUNNING:
+ return STATUS_IN_PROGRESS;
+
+ case FINISHED:
+ int result = mInstallTask.getResult();
+
+ if (result == RESULT_OK) {
+ return STATUS_READY;
+ } else {
+ throw new IllegalStateException("A failed InstallationTask is not reset");
+ }
+
+ default:
+ return STATUS_NOT_STARTED;
+ }
+ }
+
+ private boolean isInDynamicAndroid() {
+ return mDynAndroid.isInUse();
+ }
+
+ void handleMessage(Message msg) {
+ switch (msg.what) {
+ case DynamicAndroidClient.MSG_REGISTER_LISTENER:
+ try {
+ Messenger client = msg.replyTo;
+
+ int status = getStatus();
+
+ // tell just registered client my status, but do not specify cause
+ notifyOneClient(client, status, CAUSE_NOT_SPECIFIED);
+
+ mClients.add(client);
+ } catch (RemoteException e) {
+ // do nothing if we cannot send update to the client
+ e.printStackTrace();
+ }
+
+ break;
+ case DynamicAndroidClient.MSG_UNREGISTER_LISTENER:
+ mClients.remove(msg.replyTo);
+ break;
+ default:
+ // do nothing
+ }
+ }
+}
diff --git a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java
new file mode 100644
index 000000000000..3c759e948b4e
--- /dev/null
+++ b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/InstallationAsyncTask.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dynandroid;
+
+import android.os.AsyncTask;
+import android.os.DynamicAndroidManager;
+import android.util.Log;
+import android.webkit.URLUtil;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.zip.GZIPInputStream;
+
+
+class InstallationAsyncTask extends AsyncTask<String, Long, Integer> {
+
+ private static final String TAG = "InstallationAsyncTask";
+
+ private static final int READ_BUFFER_SIZE = 1 << 19;
+
+ private class InvalidImageUrlException extends RuntimeException {
+ private InvalidImageUrlException(String message) {
+ super(message);
+ }
+ }
+
+
+ /** Not completed, including being cancelled */
+ static final int NO_RESULT = 0;
+ static final int RESULT_OK = 1;
+ static final int RESULT_ERROR_IO = 2;
+ static final int RESULT_ERROR_INVALID_URL = 3;
+ static final int RESULT_ERROR_EXCEPTION = 6;
+
+ interface InstallStatusListener {
+ void onProgressUpdate(long installedSize);
+ void onResult(int resultCode);
+ void onCancelled();
+ }
+
+ private final String mUrl;
+ private final long mSystemSize;
+ private final long mUserdataSize;
+ private final DynamicAndroidManager mDynamicAndroid;
+ private final InstallStatusListener mListener;
+ private DynamicAndroidManager.Session mInstallationSession;
+
+ private long mInstalledSize;
+ private long mReportedInstalledSize;
+ private int mResult = NO_RESULT;
+
+ private InputStream mStream;
+
+
+ InstallationAsyncTask(String url, long systemSize, long userdataSize,
+ DynamicAndroidManager dynAndroid, InstallStatusListener listener) {
+ mUrl = url;
+ mSystemSize = systemSize;
+ mUserdataSize = userdataSize;
+ mDynamicAndroid = dynAndroid;
+ mListener = listener;
+ }
+
+ @Override
+ protected void onPreExecute() {
+ mListener.onProgressUpdate(0);
+ }
+
+ @Override
+ protected Integer doInBackground(String... voids) {
+ Log.d(TAG, "Start doInBackground(), URL: " + mUrl);
+
+ try {
+ // call start in background
+ mInstallationSession = mDynamicAndroid.startInstallation(mSystemSize, mUserdataSize);
+
+ if (mInstallationSession == null) {
+ Log.e(TAG, "Failed to start installation with requested size: "
+ + (mSystemSize + mUserdataSize));
+
+ return RESULT_ERROR_IO;
+ }
+
+ initInputStream();
+
+ byte[] bytes = new byte[READ_BUFFER_SIZE];
+
+ int numBytesRead;
+ long minStepToReport = mSystemSize / 100;
+
+ Log.d(TAG, "Start installation loop");
+ while ((numBytesRead = mStream.read(bytes, 0, READ_BUFFER_SIZE)) != -1) {
+ if (isCancelled()) {
+ break;
+ }
+
+ byte[] writeBuffer = numBytesRead == READ_BUFFER_SIZE
+ ? bytes : Arrays.copyOf(bytes, numBytesRead);
+
+ if (!mInstallationSession.write(writeBuffer)) {
+ throw new IOException("Failed write() to DynamicAndroid");
+ }
+
+ mInstalledSize += numBytesRead;
+
+ if (mInstalledSize > mReportedInstalledSize + minStepToReport) {
+ publishProgress(mInstalledSize);
+ mReportedInstalledSize = mInstalledSize;
+ }
+ }
+
+ return RESULT_OK;
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ return RESULT_ERROR_IO;
+
+ } catch (InvalidImageUrlException e) {
+ e.printStackTrace();
+ return RESULT_ERROR_INVALID_URL;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ return RESULT_ERROR_EXCEPTION;
+
+ } finally {
+ close();
+ }
+ }
+
+ @Override
+ protected void onCancelled() {
+ Log.d(TAG, "onCancelled(), URL: " + mUrl);
+
+ close();
+
+ mListener.onCancelled();
+ }
+
+ @Override
+ protected void onPostExecute(Integer result) {
+ Log.d(TAG, "onPostExecute(), URL: " + mUrl + ", result: " + result);
+
+ close();
+
+ mResult = result;
+ mListener.onResult(mResult);
+ }
+
+ @Override
+ protected void onProgressUpdate(Long... values) {
+ long progress = values[0];
+ mListener.onProgressUpdate(progress);
+ }
+
+ private void initInputStream() throws IOException, InvalidImageUrlException {
+ if (URLUtil.isNetworkUrl(mUrl) || URLUtil.isFileUrl(mUrl)) {
+ mStream = new BufferedInputStream(new GZIPInputStream(new URL(mUrl).openStream()));
+ } else {
+ throw new InvalidImageUrlException(
+ String.format(Locale.US, "Unsupported file source: %s", mUrl));
+ }
+ }
+
+ private void close() {
+ try {
+ if (mStream != null) {
+ mStream.close();
+ mStream = null;
+ }
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+
+ int getResult() {
+ return mResult;
+ }
+
+ boolean commit() {
+ if (mInstallationSession == null) {
+ return false;
+ }
+
+ return mInstallationSession.commit();
+ }
+}
diff --git a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/VerificationActivity.java b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/VerificationActivity.java
new file mode 100644
index 000000000000..c18c4fe689c9
--- /dev/null
+++ b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/VerificationActivity.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dynandroid;
+
+import static android.content.DynamicAndroidClient.KEY_SYSTEM_SIZE;
+import static android.content.DynamicAndroidClient.KEY_SYSTEM_URL;
+import static android.content.DynamicAndroidClient.KEY_USERDATA_SIZE;
+
+import android.app.Activity;
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.content.DynamicAndroidClient;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.util.Log;
+
+
+/**
+ * This Activity starts KeyguardManager and ask the user to confirm
+ * before any installation request. If the device is not protected by
+ * a password, it approves the request by default.
+ */
+public class VerificationActivity extends Activity {
+
+ private static final String TAG = "VerificationActivity";
+
+ private static final int REQUEST_CODE = 1;
+
+ // For install request verification
+ private static String sVerifiedUrl;
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
+
+ if (km != null) {
+ String title = getString(R.string.keyguard_title);
+ String description = getString(R.string.keyguard_description);
+ Intent intent = km.createConfirmDeviceCredentialIntent(title, description);
+
+ if (intent == null) {
+ Log.d(TAG, "This device is not protected by a password/pin");
+ startInstallationService();
+ finish();
+ } else {
+ startActivityForResult(intent, REQUEST_CODE);
+ }
+ } else {
+ finish();
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
+ startInstallationService();
+ }
+
+ finish();
+ }
+
+ private void startInstallationService() {
+ // retrieve data from calling intent
+ Intent callingIntent = getIntent();
+
+ String url = callingIntent.getStringExtra(KEY_SYSTEM_URL);
+ long systemSize = callingIntent.getLongExtra(KEY_SYSTEM_SIZE, 0);
+ long userdataSize = callingIntent.getLongExtra(KEY_USERDATA_SIZE, 0);
+
+ sVerifiedUrl = url;
+
+ // start service
+ Intent intent = new Intent(this, DynamicAndroidInstallationService.class);
+ intent.setAction(DynamicAndroidClient.ACTION_START_INSTALL);
+ intent.putExtra(KEY_SYSTEM_URL, url);
+ intent.putExtra(KEY_SYSTEM_SIZE, systemSize);
+ intent.putExtra(KEY_USERDATA_SIZE, userdataSize);
+
+ Log.d(TAG, "Starting Installation Service");
+ startServiceAsUser(intent, UserHandle.SYSTEM);
+ }
+
+ static boolean isVerified(String url) {
+ return sVerifiedUrl != null && sVerifiedUrl.equals(url);
+ }
+}
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index b6b229c770b2..c5e598d8ce46 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -230,6 +230,10 @@ public class Assistant extends NotificationAssistantService {
NotificationEntry entry =
new NotificationEntry(mPackageManager, sbn, channel, mSmsHelper);
SmartActionsHelper.SmartSuggestions suggestions = mSmartActionsHelper.suggest(entry);
+ if (DEBUG) {
+ Log.d(TAG, String.format("Creating Adjustment for %s, with %d actions, and %d replies.",
+ sbn.getKey(), suggestions.actions.size(), suggestions.replies.size()));
+ }
return createEnqueuedNotificationAdjustment(
entry, suggestions.actions, suggestions.replies);
}
diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
index 08cc39fc4935..24fa87a7f39b 100644
--- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
+++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
@@ -15,18 +15,20 @@
*/
package android.ext.services.notification;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.Notification;
import android.app.Person;
import android.app.RemoteAction;
+import android.app.RemoteInput;
import android.content.Context;
+import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.Process;
import android.service.notification.NotificationAssistantService;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.LruCache;
+import android.util.Pair;
import android.view.textclassifier.ConversationAction;
import android.view.textclassifier.ConversationActions;
import android.view.textclassifier.TextClassificationContext;
@@ -34,6 +36,8 @@ import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextClassifierEvent;
+import com.android.internal.util.ArrayUtils;
+
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
@@ -42,10 +46,13 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.List;
+import java.util.Map;
+import java.util.Objects;
import java.util.stream.Collectors;
public class SmartActionsHelper {
private static final String KEY_ACTION_TYPE = "action_type";
+ private static final String KEY_ACTION_SCORE = "action_score";
// If a notification has any of these flags set, it's inelgibile for actions being added.
private static final int FLAG_MASK_INELGIBILE_FOR_ACTIONS =
Notification.FLAG_ONGOING_EVENT
@@ -56,69 +63,136 @@ public class SmartActionsHelper {
private static final List<String> HINTS =
Collections.singletonList(ConversationActions.Request.HINT_FOR_NOTIFICATION);
+ private static final ConversationActions EMPTY_CONVERSATION_ACTIONS =
+ new ConversationActions(Collections.emptyList(), null);
private Context mContext;
- @Nullable
private TextClassifier mTextClassifier;
- @NonNull
private AssistantSettings mSettings;
- private LruCache<String, String> mNotificationKeyToResultIdCache =
- new LruCache<>(MAX_RESULT_ID_TO_CACHE);
+ private LruCache<String, Session> mSessionCache = new LruCache<>(MAX_RESULT_ID_TO_CACHE);
SmartActionsHelper(Context context, AssistantSettings settings) {
mContext = context;
TextClassificationManager textClassificationManager =
mContext.getSystemService(TextClassificationManager.class);
- if (textClassificationManager != null) {
- mTextClassifier = textClassificationManager.getTextClassifier();
- }
+ mTextClassifier = textClassificationManager.getTextClassifier();
mSettings = settings;
}
- SmartSuggestions suggest(@NonNull NotificationEntry entry) {
+ SmartSuggestions suggest(NotificationEntry entry) {
// Whenever suggest() is called on a notification, its previous session is ended.
- mNotificationKeyToResultIdCache.remove(entry.getSbn().getKey());
+ mSessionCache.remove(entry.getSbn().getKey());
boolean eligibleForReplyAdjustment =
mSettings.mGenerateReplies && isEligibleForReplyAdjustment(entry);
boolean eligibleForActionAdjustment =
mSettings.mGenerateActions && isEligibleForActionAdjustment(entry);
- List<ConversationAction> conversationActions =
+ ConversationActions conversationActionsResult =
suggestConversationActions(
entry,
eligibleForReplyAdjustment,
eligibleForActionAdjustment);
- ArrayList<CharSequence> replies = conversationActions.stream()
- .map(ConversationAction::getTextReply)
- .filter(textReply -> !TextUtils.isEmpty(textReply))
- .collect(Collectors.toCollection(ArrayList::new));
+ String resultId = conversationActionsResult.getId();
+ List<ConversationAction> conversationActions =
+ conversationActionsResult.getConversationActions();
+
+ ArrayList<CharSequence> replies = new ArrayList<>();
+ Map<CharSequence, Float> repliesScore = new ArrayMap<>();
+ for (ConversationAction conversationAction : conversationActions) {
+ CharSequence textReply = conversationAction.getTextReply();
+ if (TextUtils.isEmpty(textReply)) {
+ continue;
+ }
+ replies.add(textReply);
+ repliesScore.put(textReply, conversationAction.getConfidenceScore());
+ }
ArrayList<Notification.Action> actions = conversationActions.stream()
.filter(conversationAction -> conversationAction.getAction() != null)
- .map(action -> createNotificationAction(action.getAction(), action.getType()))
+ .map(action -> createNotificationAction(
+ action.getAction(), action.getType(), action.getConfidenceScore()))
.collect(Collectors.toCollection(ArrayList::new));
+
+ // Start a new session for logging if necessary.
+ if (!TextUtils.isEmpty(resultId)
+ && !conversationActions.isEmpty()
+ && suggestionsMightBeUsedInNotification(
+ entry, !actions.isEmpty(), !replies.isEmpty())) {
+ mSessionCache.put(entry.getSbn().getKey(), new Session(resultId, repliesScore));
+ }
+
return new SmartSuggestions(replies, actions);
}
/**
+ * Returns whether the suggestion might be used in the notifications in SysUI.
+ * <p>
+ * Currently, NAS has no idea if suggestions will actually be used in the notification, and thus
+ * this function tries to make a heuristic. This function tries to optimize the precision,
+ * that means when it is unsure, it will return false. The objective is to avoid false positive,
+ * which could pollute the log and CTR as we are logging click rate of suggestions that could
+ * be never visible to users. On the other hand, it is fine to have false negative because
+ * it would be just like sampling.
+ */
+ private boolean suggestionsMightBeUsedInNotification(
+ NotificationEntry notificationEntry, boolean hasSmartAction, boolean hasSmartReply) {
+ Notification notification = notificationEntry.getNotification();
+ boolean hasAppGeneratedContextualActions = !notification.getContextualActions().isEmpty();
+
+ Pair<RemoteInput, Notification.Action> freeformRemoteInputAndAction =
+ notification.findRemoteInputActionPair(/* requiresFreeform */ true);
+ boolean hasAppGeneratedReplies = false;
+ boolean allowGeneratedReplies = false;
+ if (freeformRemoteInputAndAction != null) {
+ RemoteInput freeformRemoteInput = freeformRemoteInputAndAction.first;
+ Notification.Action actionWithFreeformRemoteInput = freeformRemoteInputAndAction.second;
+ hasAppGeneratedReplies = !ArrayUtils.isEmpty(freeformRemoteInput.getChoices());
+ allowGeneratedReplies = actionWithFreeformRemoteInput.getAllowGeneratedReplies();
+ }
+
+ if (hasAppGeneratedReplies || hasAppGeneratedContextualActions) {
+ return false;
+ }
+ return hasSmartAction && notification.getAllowSystemGeneratedContextualActions()
+ || hasSmartReply && allowGeneratedReplies;
+ }
+
+ private void reportActionsGenerated(
+ String resultId, List<ConversationAction> conversationActions) {
+ if (TextUtils.isEmpty(resultId)) {
+ return;
+ }
+ TextClassifierEvent textClassifierEvent =
+ createTextClassifierEventBuilder(
+ TextClassifierEvent.TYPE_ACTIONS_GENERATED, resultId)
+ .setEntityTypes(conversationActions.stream()
+ .map(ConversationAction::getType)
+ .toArray(String[]::new))
+ .build();
+ mTextClassifier.onTextClassifierEvent(textClassifierEvent);
+ }
+
+ /**
* Adds action adjustments based on the notification contents.
*/
- @NonNull
- private List<ConversationAction> suggestConversationActions(
- @NonNull NotificationEntry entry,
+ private ConversationActions suggestConversationActions(
+ NotificationEntry entry,
boolean includeReplies,
boolean includeActions) {
if (!includeReplies && !includeActions) {
- return Collections.emptyList();
- }
- if (mTextClassifier == null) {
- return Collections.emptyList();
+ return EMPTY_CONVERSATION_ACTIONS;
}
List<ConversationActions.Message> messages = extractMessages(entry.getNotification());
if (messages.isEmpty()) {
- return Collections.emptyList();
+ return EMPTY_CONVERSATION_ACTIONS;
+ }
+ // Do not generate smart actions if the last message is from the local user.
+ ConversationActions.Message lastMessage = messages.get(messages.size() - 1);
+ if (arePersonsEqual(
+ ConversationActions.Message.PERSON_USER_SELF, lastMessage.getAuthor())) {
+ return EMPTY_CONVERSATION_ACTIONS;
}
TextClassifier.EntityConfig.Builder typeConfigBuilder =
@@ -138,25 +212,20 @@ public class SmartActionsHelper {
.setHints(HINTS)
.setTypeConfig(typeConfigBuilder.build())
.build();
-
- ConversationActions conversationActionsResult =
+ ConversationActions conversationActions =
mTextClassifier.suggestConversationActions(request);
-
- String resultId = conversationActionsResult.getId();
- if (!TextUtils.isEmpty(resultId)
- && !conversationActionsResult.getConversationActions().isEmpty()) {
- mNotificationKeyToResultIdCache.put(entry.getSbn().getKey(), resultId);
- }
- return conversationActionsResult.getConversationActions();
+ reportActionsGenerated(
+ conversationActions.getId(), conversationActions.getConversationActions());
+ return conversationActions;
}
- void onNotificationExpansionChanged(@NonNull NotificationEntry entry, boolean isUserAction,
+ void onNotificationExpansionChanged(NotificationEntry entry, boolean isUserAction,
boolean isExpanded) {
if (!isExpanded) {
return;
}
- String resultId = mNotificationKeyToResultIdCache.get(entry.getSbn().getKey());
- if (resultId == null) {
+ Session session = mSessionCache.get(entry.getSbn().getKey());
+ if (session == null) {
return;
}
// Only report if this is the first time the user sees these suggestions.
@@ -165,56 +234,50 @@ public class SmartActionsHelper {
}
entry.setShowActionEventLogged();
TextClassifierEvent textClassifierEvent =
- createTextClassifierEventBuilder(TextClassifierEvent.TYPE_ACTIONS_SHOWN,
- resultId)
+ createTextClassifierEventBuilder(
+ TextClassifierEvent.TYPE_ACTIONS_SHOWN, session.resultId)
.build();
// TODO: If possible, report which replies / actions are actually seen by user.
mTextClassifier.onTextClassifierEvent(textClassifierEvent);
}
- void onNotificationDirectReplied(@NonNull String key) {
- if (mTextClassifier == null) {
- return;
- }
- String resultId = mNotificationKeyToResultIdCache.get(key);
- if (resultId == null) {
+ void onNotificationDirectReplied(String key) {
+ Session session = mSessionCache.get(key);
+ if (session == null) {
return;
}
TextClassifierEvent textClassifierEvent =
- createTextClassifierEventBuilder(TextClassifierEvent.TYPE_MANUAL_REPLY, resultId)
+ createTextClassifierEventBuilder(
+ TextClassifierEvent.TYPE_MANUAL_REPLY, session.resultId)
.build();
mTextClassifier.onTextClassifierEvent(textClassifierEvent);
}
- void onSuggestedReplySent(@NonNull String key, @NonNull CharSequence reply,
+ void onSuggestedReplySent(String key, CharSequence reply,
@NotificationAssistantService.Source int source) {
- if (mTextClassifier == null) {
- return;
- }
if (source != NotificationAssistantService.SOURCE_FROM_ASSISTANT) {
return;
}
- String resultId = mNotificationKeyToResultIdCache.get(key);
- if (resultId == null) {
+ Session session = mSessionCache.get(key);
+ if (session == null) {
return;
}
TextClassifierEvent textClassifierEvent =
- createTextClassifierEventBuilder(TextClassifierEvent.TYPE_SMART_ACTION, resultId)
+ createTextClassifierEventBuilder(
+ TextClassifierEvent.TYPE_SMART_ACTION, session.resultId)
.setEntityTypes(ConversationAction.TYPE_TEXT_REPLY)
+ .setScore(session.repliesScores.getOrDefault(reply, 0f))
.build();
mTextClassifier.onTextClassifierEvent(textClassifierEvent);
}
- void onActionClicked(@NonNull String key, @NonNull Notification.Action action,
+ void onActionClicked(String key, Notification.Action action,
@NotificationAssistantService.Source int source) {
- if (mTextClassifier == null) {
- return;
- }
if (source != NotificationAssistantService.SOURCE_FROM_ASSISTANT) {
return;
}
- String resultId = mNotificationKeyToResultIdCache.get(key);
- if (resultId == null) {
+ Session session = mSessionCache.get(key);
+ if (session == null) {
return;
}
String actionType = action.getExtras().getString(KEY_ACTION_TYPE);
@@ -222,25 +285,32 @@ public class SmartActionsHelper {
return;
}
TextClassifierEvent textClassifierEvent =
- createTextClassifierEventBuilder(TextClassifierEvent.TYPE_SMART_ACTION, resultId)
+ createTextClassifierEventBuilder(
+ TextClassifierEvent.TYPE_SMART_ACTION, session.resultId)
.setEntityTypes(actionType)
.build();
mTextClassifier.onTextClassifierEvent(textClassifierEvent);
}
private Notification.Action createNotificationAction(
- RemoteAction remoteAction, String actionType) {
+ RemoteAction remoteAction, String actionType, float score) {
+ Icon icon = remoteAction.shouldShowIcon()
+ ? remoteAction.getIcon()
+ : Icon.createWithResource(mContext, com.android.internal.R.drawable.ic_action_open);
+ Bundle extras = new Bundle();
+ extras.putString(KEY_ACTION_TYPE, actionType);
+ extras.putFloat(KEY_ACTION_SCORE, score);
return new Notification.Action.Builder(
- remoteAction.getIcon(),
+ icon,
remoteAction.getTitle(),
remoteAction.getActionIntent())
.setContextual(true)
- .addExtras(Bundle.forPair(KEY_ACTION_TYPE, actionType))
+ .addExtras(extras)
.build();
}
private TextClassifierEvent.Builder createTextClassifierEventBuilder(
- int eventType, @NonNull String resultId) {
+ int eventType, String resultId) {
return new TextClassifierEvent.Builder(
TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS, eventType)
.setEventTime(System.currentTimeMillis())
@@ -258,7 +328,7 @@ public class SmartActionsHelper {
* to fundamental phone functionality where any error would result in a very negative user
* experience.
*/
- private boolean isEligibleForActionAdjustment(@NonNull NotificationEntry entry) {
+ private boolean isEligibleForActionAdjustment(NotificationEntry entry) {
Notification notification = entry.getNotification();
String pkg = entry.getSbn().getPackageName();
if (!Process.myUserHandle().equals(entry.getSbn().getUser())) {
@@ -274,7 +344,7 @@ public class SmartActionsHelper {
return entry.isMessaging();
}
- private boolean isEligibleForReplyAdjustment(@NonNull NotificationEntry entry) {
+ private boolean isEligibleForReplyAdjustment(NotificationEntry entry) {
if (!Process.myUserHandle().equals(entry.getSbn().getUser())) {
return false;
}
@@ -295,8 +365,7 @@ public class SmartActionsHelper {
}
/** Returns the text most salient for action extraction in a notification. */
- @Nullable
- private List<ConversationActions.Message> extractMessages(@NonNull Notification notification) {
+ private List<ConversationActions.Message> extractMessages(Notification notification) {
Parcelable[] messages = notification.extras.getParcelableArray(Notification.EXTRA_MESSAGES);
if (messages == null || messages.length == 0) {
return Collections.singletonList(new ConversationActions.Message.Builder(
@@ -312,13 +381,12 @@ public class SmartActionsHelper {
if (message == null) {
continue;
}
+ // As per the javadoc of Notification.addMessage, null means local user.
Person senderPerson = message.getSenderPerson();
- // Skip encoding once the sender is missing as it is important to distinguish
- // local user and remote user when generating replies.
if (senderPerson == null) {
- break;
+ senderPerson = localUser;
}
- Person author = localUser != null && localUser.equals(senderPerson)
+ Person author = localUser != null && arePersonsEqual(localUser, senderPerson)
? ConversationActions.Message.PERSON_USER_SELF : senderPerson;
extractMessages.push(new ConversationActions.Message.Builder(author)
.setText(message.getText())
@@ -333,6 +401,12 @@ public class SmartActionsHelper {
return new ArrayList<>(extractMessages);
}
+ private static boolean arePersonsEqual(Person left, Person right) {
+ return Objects.equals(left.getKey(), right.getKey())
+ && Objects.equals(left.getName(), right.getName())
+ && Objects.equals(left.getUri(), right.getUri());
+ }
+
static class SmartSuggestions {
public final ArrayList<CharSequence> replies;
public final ArrayList<Notification.Action> actions;
@@ -343,4 +417,14 @@ public class SmartActionsHelper {
this.actions = actions;
}
}
+
+ private static class Session {
+ public final String resultId;
+ public final Map<CharSequence, Float> repliesScores;
+
+ Session(String resultId, Map<CharSequence, Float> repliesScores) {
+ this.resultId = resultId;
+ this.repliesScores = repliesScores;
+ }
+ }
}
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java
index ebbd961b6f23..d0b6d0061166 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java
@@ -19,7 +19,9 @@ import static com.google.common.truth.Truth.assertAbout;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -53,8 +55,8 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.time.Instant;
@@ -71,9 +73,12 @@ import javax.annotation.Nullable;
public class SmartActionsHelperTest {
private static final String NOTIFICATION_KEY = "key";
private static final String RESULT_ID = "id";
+ private static final float SCORE = 0.7f;
+ private static final CharSequence SMART_REPLY = "Home";
private static final ConversationAction REPLY_ACTION =
new ConversationAction.Builder(ConversationAction.TYPE_TEXT_REPLY)
- .setTextReply("Home")
+ .setTextReply(SMART_REPLY)
+ .setConfidenceScore(SCORE)
.build();
private static final String MESSAGE = "Where are you?";
@@ -197,8 +202,16 @@ public class SmartActionsHelperTest {
List<ConversationActions.Message> messages =
runSuggestAndCaptureRequest().getConversation();
+
assertThat(messages).hasSize(1);
MessageSubject.assertThat(messages.get(0)).hasText(MESSAGE);
+ ArgumentCaptor<TextClassifierEvent> argumentCaptor =
+ ArgumentCaptor.forClass(TextClassifierEvent.class);
+ verify(mTextClassifier).onTextClassifierEvent(argumentCaptor.capture());
+ TextClassifierEvent textClassifierEvent = argumentCaptor.getValue();
+ assertTextClassifierEvent(textClassifierEvent, TextClassifierEvent.TYPE_ACTIONS_GENERATED);
+ assertThat(textClassifierEvent.getEntityTypes()).asList()
+ .containsExactly(ConversationAction.TYPE_TEXT_REPLY);
}
@Test
@@ -222,26 +235,63 @@ public class SmartActionsHelperTest {
List<ConversationActions.Message> messages =
runSuggestAndCaptureRequest().getConversation();
- assertThat(messages).hasSize(3);
+ assertThat(messages).hasSize(4);
+
+ ConversationActions.Message firstMessage = messages.get(0);
+ MessageSubject.assertThat(firstMessage).hasText("firstMessage");
+ MessageSubject.assertThat(firstMessage)
+ .hasPerson(ConversationActions.Message.PERSON_USER_SELF);
+ MessageSubject.assertThat(firstMessage)
+ .hasReferenceTime(createZonedDateTimeFromMsUtc(1000));
- ConversationActions.Message secondMessage = messages.get(0);
+ ConversationActions.Message secondMessage = messages.get(1);
MessageSubject.assertThat(secondMessage).hasText("secondMessage");
MessageSubject.assertThat(secondMessage)
.hasPerson(ConversationActions.Message.PERSON_USER_SELF);
MessageSubject.assertThat(secondMessage)
.hasReferenceTime(createZonedDateTimeFromMsUtc(2000));
- ConversationActions.Message thirdMessage = messages.get(1);
+ ConversationActions.Message thirdMessage = messages.get(2);
MessageSubject.assertThat(thirdMessage).hasText("thirdMessage");
MessageSubject.assertThat(thirdMessage).hasPerson(userA);
MessageSubject.assertThat(thirdMessage)
.hasReferenceTime(createZonedDateTimeFromMsUtc(3000));
- ConversationActions.Message fourthMessage = messages.get(2);
+ ConversationActions.Message fourthMessage = messages.get(3);
MessageSubject.assertThat(fourthMessage).hasText("fourthMessage");
MessageSubject.assertThat(fourthMessage).hasPerson(userB);
MessageSubject.assertThat(fourthMessage)
.hasReferenceTime(createZonedDateTimeFromMsUtc(4000));
+
+ ArgumentCaptor<TextClassifierEvent> argumentCaptor =
+ ArgumentCaptor.forClass(TextClassifierEvent.class);
+ verify(mTextClassifier).onTextClassifierEvent(argumentCaptor.capture());
+ TextClassifierEvent textClassifierEvent = argumentCaptor.getValue();
+ assertTextClassifierEvent(textClassifierEvent, TextClassifierEvent.TYPE_ACTIONS_GENERATED);
+ assertThat(textClassifierEvent.getEntityTypes()).asList()
+ .containsExactly(ConversationAction.TYPE_TEXT_REPLY);
+ }
+
+ @Test
+ public void testSuggest_lastMessageLocalUser() {
+ Person me = new Person.Builder().setName("Me").build();
+ Person userA = new Person.Builder().setName("A").build();
+ Notification.MessagingStyle style =
+ new Notification.MessagingStyle(me)
+ .addMessage("firstMessage", 1000, userA)
+ .addMessage("secondMessage", 2000, me);
+ Notification notification =
+ mNotificationBuilder
+ .setContentText("You have two new messages")
+ .setStyle(style)
+ .setActions(createReplyAction())
+ .build();
+ when(mStatusBarNotification.getNotification()).thenReturn(notification);
+
+ mSmartActionsHelper.suggest(createNotificationEntry());
+
+ verify(mTextClassifier, never())
+ .suggestConversationActions(any(ConversationActions.Request.class));
}
@Test
@@ -270,13 +320,15 @@ public class SmartActionsHelperTest {
mSmartActionsHelper.suggest(createNotificationEntry());
mSmartActionsHelper.onSuggestedReplySent(
- NOTIFICATION_KEY, MESSAGE, NotificationAssistantService.SOURCE_FROM_ASSISTANT);
+ NOTIFICATION_KEY, SMART_REPLY, NotificationAssistantService.SOURCE_FROM_ASSISTANT);
ArgumentCaptor<TextClassifierEvent> argumentCaptor =
ArgumentCaptor.forClass(TextClassifierEvent.class);
- verify(mTextClassifier).onTextClassifierEvent(argumentCaptor.capture());
- TextClassifierEvent textClassifierEvent = argumentCaptor.getValue();
- assertTextClassifierEvent(textClassifierEvent, TextClassifierEvent.TYPE_SMART_ACTION);
+ verify(mTextClassifier, times(2)).onTextClassifierEvent(argumentCaptor.capture());
+ List<TextClassifierEvent> events = argumentCaptor.getAllValues();
+ assertTextClassifierEvent(events.get(0), TextClassifierEvent.TYPE_ACTIONS_GENERATED);
+ assertTextClassifierEvent(events.get(1), TextClassifierEvent.TYPE_SMART_ACTION);
+ assertThat(events.get(1).getScore()).isEqualTo(SCORE);
}
@Test
@@ -288,24 +340,22 @@ public class SmartActionsHelperTest {
mSmartActionsHelper.onSuggestedReplySent(
"something_else", MESSAGE, NotificationAssistantService.SOURCE_FROM_ASSISTANT);
- verify(mTextClassifier, never())
- .onTextClassifierEvent(Mockito.any(TextClassifierEvent.class));
+ verify(mTextClassifier, never()).onTextClassifierEvent(
+ argThat(new TextClassifierEventMatcher(TextClassifierEvent.TYPE_SMART_ACTION)));
}
@Test
public void testOnSuggestedReplySent_missingResultId() {
when(mTextClassifier.suggestConversationActions(any(ConversationActions.Request.class)))
- .thenReturn(new ConversationActions(Collections.emptyList(), null));
-
+ .thenReturn(new ConversationActions(Collections.singletonList(REPLY_ACTION), null));
Notification notification = createMessageNotification();
when(mStatusBarNotification.getNotification()).thenReturn(notification);
mSmartActionsHelper.suggest(createNotificationEntry());
mSmartActionsHelper.onSuggestedReplySent(
- "something_else", MESSAGE, NotificationAssistantService.SOURCE_FROM_ASSISTANT);
+ NOTIFICATION_KEY, SMART_REPLY, NotificationAssistantService.SOURCE_FROM_ASSISTANT);
- verify(mTextClassifier, never())
- .onTextClassifierEvent(Mockito.any(TextClassifierEvent.class));
+ verify(mTextClassifier, never()).onTextClassifierEvent(any(TextClassifierEvent.class));
}
@Test
@@ -318,9 +368,10 @@ public class SmartActionsHelperTest {
ArgumentCaptor<TextClassifierEvent> argumentCaptor =
ArgumentCaptor.forClass(TextClassifierEvent.class);
- verify(mTextClassifier).onTextClassifierEvent(argumentCaptor.capture());
- TextClassifierEvent textClassifierEvent = argumentCaptor.getValue();
- assertTextClassifierEvent(textClassifierEvent, TextClassifierEvent.TYPE_MANUAL_REPLY);
+ verify(mTextClassifier, times(2)).onTextClassifierEvent(argumentCaptor.capture());
+ List<TextClassifierEvent> events = argumentCaptor.getAllValues();
+ assertTextClassifierEvent(events.get(0), TextClassifierEvent.TYPE_ACTIONS_GENERATED);
+ assertTextClassifierEvent(events.get(1), TextClassifierEvent.TYPE_MANUAL_REPLY);
}
@Test
@@ -333,9 +384,10 @@ public class SmartActionsHelperTest {
ArgumentCaptor<TextClassifierEvent> argumentCaptor =
ArgumentCaptor.forClass(TextClassifierEvent.class);
- verify(mTextClassifier).onTextClassifierEvent(argumentCaptor.capture());
- TextClassifierEvent textClassifierEvent = argumentCaptor.getValue();
- assertTextClassifierEvent(textClassifierEvent, TextClassifierEvent.TYPE_ACTIONS_SHOWN);
+ verify(mTextClassifier, times(2)).onTextClassifierEvent(argumentCaptor.capture());
+ List<TextClassifierEvent> events = argumentCaptor.getAllValues();
+ assertTextClassifierEvent(events.get(0), TextClassifierEvent.TYPE_ACTIONS_GENERATED);
+ assertTextClassifierEvent(events.get(1), TextClassifierEvent.TYPE_ACTIONS_SHOWN);
}
@Test
@@ -347,7 +399,7 @@ public class SmartActionsHelperTest {
mSmartActionsHelper.onNotificationExpansionChanged(createNotificationEntry(), false, false);
verify(mTextClassifier, never()).onTextClassifierEvent(
- Mockito.any(TextClassifierEvent.class));
+ argThat(new TextClassifierEventMatcher(TextClassifierEvent.TYPE_ACTIONS_SHOWN)));
}
@Test
@@ -360,9 +412,10 @@ public class SmartActionsHelperTest {
ArgumentCaptor<TextClassifierEvent> argumentCaptor =
ArgumentCaptor.forClass(TextClassifierEvent.class);
- verify(mTextClassifier).onTextClassifierEvent(argumentCaptor.capture());
- TextClassifierEvent textClassifierEvent = argumentCaptor.getValue();
- assertTextClassifierEvent(textClassifierEvent, TextClassifierEvent.TYPE_ACTIONS_SHOWN);
+ verify(mTextClassifier, times(2)).onTextClassifierEvent(argumentCaptor.capture());
+ List<TextClassifierEvent> events = argumentCaptor.getAllValues();
+ assertTextClassifierEvent(events.get(0), TextClassifierEvent.TYPE_ACTIONS_GENERATED);
+ assertTextClassifierEvent(events.get(1), TextClassifierEvent.TYPE_ACTIONS_SHOWN);
}
private ZonedDateTime createZonedDateTimeFromMsUtc(long msUtc) {
@@ -461,4 +514,21 @@ public class SmartActionsHelperTest {
return assertAbout(FACTORY).that(message);
}
}
+
+ private final class TextClassifierEventMatcher implements ArgumentMatcher<TextClassifierEvent> {
+
+ private int mType;
+
+ private TextClassifierEventMatcher(int type) {
+ mType = type;
+ }
+
+ @Override
+ public boolean matches(TextClassifierEvent textClassifierEvent) {
+ if (textClassifierEvent == null) {
+ return false;
+ }
+ return mType == textClassifierEvent.getEventType();
+ }
+ }
}
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
index ac55bfa1aed7..860ebfbf6da7 100644
--- a/packages/NetworkStack/AndroidManifest.xml
+++ b/packages/NetworkStack/AndroidManifest.xml
@@ -27,10 +27,11 @@
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />
<!-- Signature permission defined in NetworkStackStub -->
<uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" />
- <!-- Launch captive portal app as specific user -->
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <!-- Send latency broadcast as current user -->
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.NETWORK_STACK" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
<application
android:label="NetworkStack"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java
index 9e5991298834..b1f6d246563e 100644
--- a/packages/NetworkStack/src/android/net/ip/IpClient.java
+++ b/packages/NetworkStack/src/android/net/ip/IpClient.java
@@ -46,6 +46,7 @@ import android.net.shared.ProvisioningConfiguration;
import android.net.util.InterfaceParams;
import android.net.util.SharedLog;
import android.os.ConditionVariable;
+import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -380,6 +381,13 @@ public class IpClient extends StateMachine {
public InterfaceParams getInterfaceParams(String ifname) {
return InterfaceParams.getByName(ifname);
}
+
+ /**
+ * Get a INetd connector.
+ */
+ public INetd getNetd(Context context) {
+ return INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE));
+ }
}
public IpClient(Context context, String ifName, IIpClientCallbacks callback,
@@ -413,7 +421,7 @@ public class IpClient extends StateMachine {
// TODO: Consider creating, constructing, and passing in some kind of
// InterfaceController.Dependencies class.
- mNetd = mContext.getSystemService(INetd.class);
+ mNetd = deps.getNetd(mContext);
mInterfaceCtrl = new InterfaceController(mInterfaceName, mNetd, mLog);
mLinkObserver = new IpClientLinkObserver(
diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
index cedcb84e9d08..c6a207f26577 100644
--- a/packages/NetworkStack/src/com/android/server/NetworkStackService.java
+++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
@@ -114,7 +114,8 @@ public class NetworkStackService extends Service {
NetworkStackConnector(Context context) {
mContext = context;
- mNetd = (INetd) context.getSystemService(Context.NETD_SERVICE);
+ mNetd = INetd.Stub.asInterface(
+ (IBinder) context.getSystemService(Context.NETD_SERVICE));
mObserverRegistry = new NetworkObserverRegistry();
mCm = context.getSystemService(ConnectivityManager.class);
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index 0d6d080b6dc2..b9e901b5c5e3 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -67,15 +67,9 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
-import android.telephony.CellIdentityCdma;
-import android.telephony.CellIdentityGsm;
-import android.telephony.CellIdentityLte;
-import android.telephony.CellIdentityWcdma;
-import android.telephony.CellInfo;
-import android.telephony.CellInfoCdma;
-import android.telephony.CellInfoGsm;
-import android.telephony.CellInfoLte;
-import android.telephony.CellInfoWcdma;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.NetworkRegistrationState;
+import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
@@ -500,7 +494,7 @@ public class NetworkMonitor extends StateMachine {
private void showProvisioningNotification(String action) {
try {
- mCallback.showProvisioningNotification(action);
+ mCallback.showProvisioningNotification(action, mContext.getPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Error showing provisioning notification", e);
}
@@ -1312,6 +1306,7 @@ public class NetworkMonitor extends StateMachine {
urlConnection.setInstanceFollowRedirects(probeType == ValidationProbeEvent.PROBE_PAC);
urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
+ urlConnection.setRequestProperty("Connection", "close");
urlConnection.setUseCaches(false);
if (mCaptivePortalUserAgent != null) {
urlConnection.setRequestProperty("User-Agent", mCaptivePortalUserAgent);
@@ -1485,10 +1480,6 @@ public class NetworkMonitor extends StateMachine {
*/
private void sendNetworkConditionsBroadcast(boolean responseReceived, boolean isCaptivePortal,
long requestTimestampMs, long responseTimestampMs) {
- if (!mWifiManager.isScanAlwaysAvailable()) {
- return;
- }
-
if (!mSystemReady) {
return;
}
@@ -1496,6 +1487,10 @@ public class NetworkMonitor extends StateMachine {
Intent latencyBroadcast =
new Intent(NetworkMonitorUtils.ACTION_NETWORK_CONDITIONS_MEASURED);
if (mNetworkCapabilities.hasTransport(TRANSPORT_WIFI)) {
+ if (!mWifiManager.isScanAlwaysAvailable()) {
+ return;
+ }
+
WifiInfo currentWifiInfo = mWifiManager.getConnectionInfo();
if (currentWifiInfo != null) {
// NOTE: getSSID()'s behavior changed in API 17; before that, SSIDs were not
@@ -1515,39 +1510,21 @@ public class NetworkMonitor extends StateMachine {
}
latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CONNECTIVITY_TYPE, TYPE_WIFI);
} else if (mNetworkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
+ // TODO(b/123893112): Support multi-sim.
latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_NETWORK_TYPE,
mTelephonyManager.getNetworkType());
- List<CellInfo> info = mTelephonyManager.getAllCellInfo();
- if (info == null) return;
- int numRegisteredCellInfo = 0;
- for (CellInfo cellInfo : info) {
- if (cellInfo.isRegistered()) {
- numRegisteredCellInfo++;
- if (numRegisteredCellInfo > 1) {
- if (VDBG) {
- logw("more than one registered CellInfo."
- + " Can't tell which is active. Bailing.");
- }
- return;
- }
- if (cellInfo instanceof CellInfoCdma) {
- CellIdentityCdma cellId = ((CellInfoCdma) cellInfo).getCellIdentity();
- latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CELL_ID, cellId);
- } else if (cellInfo instanceof CellInfoGsm) {
- CellIdentityGsm cellId = ((CellInfoGsm) cellInfo).getCellIdentity();
- latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CELL_ID, cellId);
- } else if (cellInfo instanceof CellInfoLte) {
- CellIdentityLte cellId = ((CellInfoLte) cellInfo).getCellIdentity();
- latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CELL_ID, cellId);
- } else if (cellInfo instanceof CellInfoWcdma) {
- CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity();
- latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CELL_ID, cellId);
- } else {
- if (VDBG) logw("Registered cellinfo is unrecognized");
- return;
- }
- }
+ final ServiceState dataSs = mTelephonyManager.getServiceState();
+ if (dataSs == null) {
+ logw("failed to retrieve ServiceState");
+ return;
}
+ // See if the data sub is registered for PS services on cell.
+ final NetworkRegistrationState nrs = dataSs.getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_PS,
+ AccessNetworkConstants.TransportType.WWAN);
+ latencyBroadcast.putExtra(
+ NetworkMonitorUtils.EXTRA_CELL_ID,
+ nrs == null ? null : nrs.getCellIdentity());
latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CONNECTIVITY_TYPE, TYPE_MOBILE);
} else {
return;
diff --git a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
index 7e57d1eb00b0..aaaff0279fed 100644
--- a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
+++ b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
@@ -104,8 +104,8 @@ public class IpClientTest {
when(mContext.getSystemService(eq(Context.ALARM_SERVICE))).thenReturn(mAlarm);
when(mContext.getSystemService(eq(ConnectivityManager.class))).thenReturn(mCm);
- when(mContext.getSystemService(INetd.class)).thenReturn(mNetd);
when(mContext.getResources()).thenReturn(mResources);
+ when(mDependencies.getNetd(any())).thenReturn(mNetd);
when(mResources.getInteger(R.integer.config_networkAvoidBadWifi))
.thenReturn(DEFAULT_AVOIDBADWIFI_CONFIG_VALUE);
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
index d11bb64213c3..b98b0f798fe3 100644
--- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -482,7 +482,7 @@ public class NetworkMonitorTest {
nm.notifyNetworkConnected();
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .showProvisioningNotification(any());
+ .showProvisioningNotification(any(), any());
// Check that startCaptivePortalApp sends the expected intent.
nm.launchCaptivePortalApp();
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 36ee81308e98..caa928f43cc9 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -21,6 +21,7 @@ android_library {
"SettingsLibActionButtonsPreference",
"SettingsLibEntityHeaderWidgets",
"SettingsLibBarChartPreference",
+ "SettingsLibProgressBar",
],
// ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
diff --git a/packages/SettingsLib/AppPreference/res/layout/preference_app.xml b/packages/SettingsLib/AppPreference/res/layout/preference_app.xml
index 6d35550f1b77..b198f5a35630 100644
--- a/packages/SettingsLib/AppPreference/res/layout/preference_app.xml
+++ b/packages/SettingsLib/AppPreference/res/layout/preference_app.xml
@@ -52,7 +52,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
- android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+ android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee"
android:fadingEdge="horizontal"/>
@@ -65,7 +65,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:textAppearance="@android:style/TextAppearance.Material.Small"
+ android:textAppearance="?android:attr/textAppearanceSmall"
android:textAlignment="viewStart"
android:textColor="?android:attr/textColorSecondary"/>
@@ -73,7 +73,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:textAppearance="@android:style/TextAppearance.Material.Small"
+ android:textAppearance="?android:attr/textAppearanceSmall"
android:textAlignment="viewEnd"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="1"
diff --git a/packages/SettingsLib/EntityHeaderWidgets/res/layout/app_view.xml b/packages/SettingsLib/EntityHeaderWidgets/res/layout/app_view.xml
index 96045120fec4..013d2d004471 100644
--- a/packages/SettingsLib/EntityHeaderWidgets/res/layout/app_view.xml
+++ b/packages/SettingsLib/EntityHeaderWidgets/res/layout/app_view.xml
@@ -23,7 +23,7 @@
android:layout_marginEnd="16dp"
android:gravity="center"
android:clickable="true"
- android:background="?android:attr/selectableItemBackground"
+ android:background="@*android:drawable/btn_borderless_material"
android:orientation="vertical">
<ImageView
diff --git a/packages/SettingsLib/ProgressBar/Android.bp b/packages/SettingsLib/ProgressBar/Android.bp
new file mode 100644
index 000000000000..eae21d8858dc
--- /dev/null
+++ b/packages/SettingsLib/ProgressBar/Android.bp
@@ -0,0 +1,9 @@
+android_library {
+ name: "SettingsLibProgressBar",
+
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+
+ sdk_version: "system_current",
+ min_sdk_version: "21",
+} \ No newline at end of file
diff --git a/packages/SettingsLib/ProgressBar/AndroidManifest.xml b/packages/SettingsLib/ProgressBar/AndroidManifest.xml
new file mode 100644
index 000000000000..256b8f3ea477
--- /dev/null
+++ b/packages/SettingsLib/ProgressBar/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.settingslib.widget">
+
+ <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/ProgressBar/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml b/packages/SettingsLib/ProgressBar/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml
new file mode 100644
index 000000000000..2b7535ab91d1
--- /dev/null
+++ b/packages/SettingsLib/ProgressBar/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- Variant of progress_indeterminate_horizontal_material in frameworks/base/core/res, which
+ draws the whole height of the progress bar instead having blank space above and below the
+ bar. -->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/vector_drawable_progress_indeterminate_horizontal_trimmed" >
+ <target
+ android:name="rect2_grp"
+ android:animation="@*android:anim/progress_indeterminate_horizontal_rect2" />
+ <target
+ android:name="rect1_grp"
+ android:animation="@*android:anim/progress_indeterminate_horizontal_rect1" />
+</animated-vector> \ No newline at end of file
diff --git a/packages/SettingsLib/ProgressBar/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml b/packages/SettingsLib/ProgressBar/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml
new file mode 100644
index 000000000000..2f604d0301ba
--- /dev/null
+++ b/packages/SettingsLib/ProgressBar/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- Variant of vector_drawable_progress_indeterminate_horizontal in frameworks/base/core/res, which
+ draws the whole height of the progress bar instead having blank space above and below the
+ bar. -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="10dp"
+ android:width="360dp"
+ android:viewportHeight="10"
+ android:viewportWidth="360" >
+ <group
+ android:name="progress_group"
+ android:translateX="180"
+ android:translateY="5" >
+ <path
+ android:name="background_track"
+ android:pathData="M -180.0,-5.0 l 360.0,0 l 0,10.0 l -360.0,0 Z"
+ android:fillColor="?android:attr/colorControlActivated"
+ android:fillAlpha="?android:attr/disabledAlpha"/>
+ <group
+ android:name="rect2_grp"
+ android:translateX="-197.60001"
+ android:scaleX="0.1" >
+ <path
+ android:name="rect2"
+ android:pathData="M -144.0,-5.0 l 288.0,0 l 0,10.0 l -288.0,0 Z"
+ android:fillColor="?android:attr/colorControlActivated" />
+ </group>
+ <group
+ android:name="rect1_grp"
+ android:translateX="-522.59998"
+ android:scaleX="0.1" >
+ <path
+ android:name="rect1"
+ android:pathData="M -144.0,-5.0 l 288.0,0 l 0,10.0 l -288.0,0 Z"
+ android:fillColor="?android:attr/colorControlActivated" />
+ </group>
+ </group>
+</vector> \ No newline at end of file
diff --git a/packages/SettingsLib/ProgressBar/res/layout/progress_header.xml b/packages/SettingsLib/ProgressBar/res/layout/progress_header.xml
new file mode 100644
index 000000000000..268858bebf0c
--- /dev/null
+++ b/packages/SettingsLib/ProgressBar/res/layout/progress_header.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="3dp">
+ <View
+ android:id="@+id/progress_bar_background"
+ style="@style/TrimmedHorizontalProgressBar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/colorSecondary" />
+ <ProgressBar
+ android:id="@+id/progress_bar_animation"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/TrimmedHorizontalProgressBar"
+ android:indeterminate="true" />
+</FrameLayout> \ No newline at end of file
diff --git a/media/packages/MediaCore/res/values/strings.xml b/packages/SettingsLib/ProgressBar/res/values/styles.xml
index 59fd635b905f..5f57c1db0238 100644
--- a/media/packages/MediaCore/res/values/strings.xml
+++ b/packages/SettingsLib/ProgressBar/res/values/styles.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2019 The Android Open Source Project
+<!-- Copyright (C) 2019 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,7 +15,14 @@
-->
<resources>
- <!-- Label for the Android system components when they are shown to the user. -->
- <string name="android_system_label" translatable="false">Android System</string>
-</resources>
+ <style name="TrimmedHorizontalProgressBar"
+ parent="android:Widget.Material.ProgressBar.Horizontal">
+ <item name="android:indeterminateDrawable">
+ @drawable/progress_indeterminate_horizontal_material_trimmed
+ </item>
+ <item name="android:minHeight">3dp</item>
+ <item name="android:maxHeight">3dp</item>
+ </style>
+
+</resources> \ No newline at end of file
diff --git a/packages/SettingsLib/res/drawable/ic_info_outline_24.xml b/packages/SettingsLib/res/drawable/ic_info_outline_24.xml
new file mode 100644
index 000000000000..317e43b95cdd
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_info_outline_24.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorControlNormal">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_system_update.xml b/packages/SettingsLib/res/drawable/ic_system_update.xml
new file mode 100644
index 000000000000..3325fdd5c01a
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_system_update.xml
@@ -0,0 +1,25 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorControlNormal">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,21H7l0,-1h10V21zM17,18H7V6h10V18zM7,4V3h10v1H7zM16,12.5l-4,4l-4,-4l1.41,-1.41L11,12.67V8.5V8h2v0.5v4.17l1.59,-1.59L16,12.5z"/>
+</vector>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index d6448336e402..f5d58d8a2004 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -337,6 +337,9 @@
<string name="data_usage_uninstalled_apps">Removed apps</string>
<!-- Title of data usage item that represents all uninstalled applications or removed users. [CHAR LIMIT=48] -->
<string name="data_usage_uninstalled_apps_users">Removed apps and users</string>
+ <!-- Title of data usage item that represents system updates (OTAs). [CHAR LIMIT=48] -->
+ <string name="data_usage_ota">System updates</string>
+
<!-- Tethering controls, item title to go into the tethering settings -->
<!-- Tethering controls, item title to go into the tethering settings when only USB tethering is available [CHAR LIMIT=25]-->
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index e28c894ff8f3..ab95910a77b5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -167,7 +167,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
// This is to ensure all the profiles are disconnected as some CK/Hs do not
// disconnect PBAP connection when HF connection is brought down
PbapServerProfile PbapProfile = mProfileManager.getPbapProfile();
- if (PbapProfile.getConnectionStatus(mDevice) == BluetoothProfile.STATE_CONNECTED)
+ if (PbapProfile != null && isConnectedProfile(PbapProfile))
{
PbapProfile.disconnect(mDevice);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index a1bf93654774..c1933fd87633 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -73,9 +73,8 @@ public class HeadsetProfile implements LocalBluetoothProfile {
BluetoothProfile.STATE_CONNECTED);
device.refresh();
}
-
- mProfileManager.callServiceConnectedListeners();
mIsProfileReady=true;
+ mProfileManager.callServiceConnectedListeners();
}
public void onServiceDisconnected(int profile) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java
index 305a1ff97e71..dd6d563b3197 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleDataLoader.java
@@ -40,6 +40,7 @@ import androidx.loader.content.AsyncTaskLoader;
import com.android.settingslib.NetworkPolicyEditor;
import java.time.ZonedDateTime;
+import java.util.ArrayList;
import java.util.Iterator;
/**
@@ -52,6 +53,7 @@ public abstract class NetworkCycleDataLoader<D> extends AsyncTaskLoader<D> {
protected final int mNetworkType;
private final NetworkPolicy mPolicy;
private final NetworkTemplate mNetworkTemplate;
+ private final ArrayList<Long> mCycles;
@VisibleForTesting
final INetworkStatsService mNetworkStatsService;
@@ -60,6 +62,7 @@ public abstract class NetworkCycleDataLoader<D> extends AsyncTaskLoader<D> {
mSubId = builder.mSubId;
mNetworkType = builder.mNetworkType;
mNetworkTemplate = builder.mNetworkTemplate;
+ mCycles = builder.mCycles;
mNetworkStatsManager = (NetworkStatsManager)
builder.mContext.getSystemService(Context.NETWORK_STATS_SERVICE);
mNetworkStatsService = INetworkStatsService.Stub.asInterface(
@@ -77,7 +80,9 @@ public abstract class NetworkCycleDataLoader<D> extends AsyncTaskLoader<D> {
}
public D loadInBackground() {
- if (mPolicy == null) {
+ if (mCycles != null && mCycles.size() > 1) {
+ loadDataForSpecificCycles();
+ } else if (mPolicy == null) {
loadFourWeeksData();
} else {
loadPolicyData();
@@ -132,6 +137,17 @@ public abstract class NetworkCycleDataLoader<D> extends AsyncTaskLoader<D> {
}
@VisibleForTesting
+ void loadDataForSpecificCycles() {
+ long cycleEnd = mCycles.get(0);
+ final int lastCycleIndex = mCycles.size() - 1;
+ for (int i = 1; i <= lastCycleIndex; i++) {
+ final long cycleStart = mCycles.get(i);
+ recordUsage(cycleStart, cycleEnd);
+ cycleEnd = cycleStart;
+ }
+ }
+
+ @VisibleForTesting
abstract void recordUsage(long start, long end);
abstract D getCycleUsage();
@@ -157,11 +173,17 @@ public abstract class NetworkCycleDataLoader<D> extends AsyncTaskLoader<D> {
return bytes;
}
+ @VisibleForTesting(otherwise = VisibleForTesting.NONE)
+ public ArrayList<Long> getCycles() {
+ return mCycles;
+ }
+
public static abstract class Builder<T extends NetworkCycleDataLoader> {
private final Context mContext;
private String mSubId;
private int mNetworkType;
private NetworkTemplate mNetworkTemplate;
+ private ArrayList<Long> mCycles;
public Builder (Context context) {
mContext = context;
@@ -178,6 +200,16 @@ public abstract class NetworkCycleDataLoader<D> extends AsyncTaskLoader<D> {
return this;
}
+ /**
+ * Sets the network cycles to be used to query the usage data.
+ * @param cycles the time slots for the network cycle to be used to query the network usage.
+ * @return the builder
+ */
+ public Builder<T> setCycles(ArrayList<Long> cycles) {
+ mCycles = cycles;
+ return this;
+ }
+
public abstract T build();
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java
index c14f5588cddf..e3516158daac 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java
@@ -28,6 +28,7 @@ import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.TrafficStats;
+import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -111,7 +112,7 @@ public class UidDetailProvider {
// handle special case labels
switch (uid) {
- case android.os.Process.SYSTEM_UID:
+ case Process.SYSTEM_UID:
detail.label = res.getString(R.string.process_kernel_label);
detail.icon = pm.getDefaultActivityIcon();
return detail;
@@ -127,6 +128,10 @@ public class UidDetailProvider {
detail.label = res.getString(Utils.getTetheringLabel(cm));
detail.icon = pm.getDefaultActivityIcon();
return detail;
+ case Process.OTA_UPDATE_UID:
+ detail.label = res.getString(R.string.data_usage_ota);
+ detail.icon = mContext.getDrawable(R.drawable.ic_system_update);
+ return detail;
}
final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
index 88adcdb16edc..5c9a06f91e6a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
@@ -20,6 +20,7 @@ import android.os.Looper;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
public class ThreadUtils {
@@ -59,12 +60,14 @@ public class ThreadUtils {
/**
* Posts runnable in background using shared background thread pool.
+ *
+ * @Return A future of the task that can be monitored for updates or cancelled.
*/
- public static void postOnBackgroundThread(Runnable runnable) {
+ public static Future postOnBackgroundThread(Runnable runnable) {
if (sSingleThreadExecutor == null) {
sSingleThreadExecutor = Executors.newSingleThreadExecutor();
}
- sSingleThreadExecutor.execute(runnable);
+ return sSingleThreadExecutor.submit(runnable);
}
/**
diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
index a106846fac26..2a1281027169 100644
--- a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
@@ -56,7 +56,7 @@ public class FooterPreference extends Preference {
}
private void init() {
- setIcon(com.android.internal.R.drawable.ic_info_outline_24);
+ setIcon(R.drawable.ic_info_outline_24);
setKey(KEY_FOOTER);
setOrder(ORDER_FOOTER);
setSelectable(false);
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index b9a5f2347f16..8ea0f4b6ba61 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -53,6 +53,7 @@ import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import com.android.internal.util.CollectionUtils;
import com.android.settingslib.R;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -566,9 +567,6 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
AccessPoint accessPoint =
getCachedOrCreate(entry.getValue(), cachedAccessPoints);
- if (mLastInfo != null && mLastNetworkInfo != null) {
- accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
- }
// Update the matching config if there is one, to populate saved network info
accessPoint.update(configsByKey.get(entry.getKey()));
@@ -578,68 +576,20 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
List<ScanResult> cachedScanResults = new ArrayList<>(mScanResultCache.values());
- // Add a unique Passpoint R1 AccessPoint for each Passpoint profile's FQDN.
- List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> passpointConfigsAndScans =
- mWifiManager.getAllMatchingWifiConfigs(cachedScanResults);
- Set<String> seenFQDNs = new ArraySet<>();
- for (Pair<WifiConfiguration,
- Map<Integer, List<ScanResult>>> pairing : passpointConfigsAndScans) {
- WifiConfiguration config = pairing.first;
-
- List<ScanResult> scanResults = new ArrayList<>();
+ // Add a unique Passpoint AccessPoint for each Passpoint profile's FQDN.
+ accessPoints.addAll(updatePasspointAccessPoints(
+ mWifiManager.getAllMatchingWifiConfigs(cachedScanResults), cachedAccessPoints));
- List<ScanResult> homeScans =
- pairing.second.get(WifiManager.PASSPOINT_HOME_NETWORK);
- List<ScanResult> roamingScans =
- pairing.second.get(WifiManager.PASSPOINT_ROAMING_NETWORK);
+ // Add OSU Provider AccessPoints
+ accessPoints.addAll(updateOsuAccessPoints(
+ mWifiManager.getMatchingOsuProviders(cachedScanResults), cachedAccessPoints));
- if (homeScans == null) {
- homeScans = new ArrayList<>();
- }
- if (roamingScans == null) {
- roamingScans = new ArrayList<>();
- }
-
- // TODO(b/118705403): Differentiate home network vs roaming network for summary info
- if (!homeScans.isEmpty()) {
- scanResults.addAll(homeScans);
- } else {
- scanResults.addAll(roamingScans);
- }
-
- if (seenFQDNs.add(config.FQDN)) {
- int bestRssi = Integer.MIN_VALUE;
- for (ScanResult result : scanResults) {
- if (result.level >= bestRssi) {
- bestRssi = result.level;
- config.SSID = AccessPoint.convertToQuotedString(result.SSID);
- }
- }
-
- AccessPoint accessPoint =
- getCachedOrCreatePasspoint(scanResults, cachedAccessPoints, config);
- accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
- accessPoints.add(accessPoint);
- }
- }
-
- // Add Passpoint OSU Provider AccessPoints
- Map<OsuProvider, List<ScanResult>> providersAndScans =
- mWifiManager.getMatchingOsuProviders(cachedScanResults);
- Set<OsuProvider> alreadyProvisioned = mWifiManager
- .getMatchingPasspointConfigsForOsuProviders(
- providersAndScans.keySet()).keySet();
- for (OsuProvider provider : providersAndScans.keySet()) {
- if (!alreadyProvisioned.contains(provider)) {
- AccessPoint accessPointOsu =
- getCachedOrCreateOsu(providersAndScans.get(provider),
- cachedAccessPoints, provider);
- accessPointOsu.update(connectionConfig, mLastInfo, mLastNetworkInfo);
- accessPoints.add(accessPointOsu);
+ if (mLastInfo != null && mLastNetworkInfo != null) {
+ for (AccessPoint ap : accessPoints) {
+ ap.update(connectionConfig, mLastInfo, mLastNetworkInfo);
}
}
-
// If there were no scan results, create an AP for the currently connected network (if
// it exists).
if (accessPoints.isEmpty() && connectionConfig != null) {
@@ -686,7 +636,67 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
}
@VisibleForTesting
- AccessPoint getCachedOrCreate(
+ List<AccessPoint> updatePasspointAccessPoints(
+ List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> passpointConfigsAndScans,
+ List<AccessPoint> accessPointCache) {
+ List<AccessPoint> accessPoints = new ArrayList<>();
+
+ Set<String> seenFQDNs = new ArraySet<>();
+ for (Pair<WifiConfiguration,
+ Map<Integer, List<ScanResult>>> pairing : passpointConfigsAndScans) {
+ WifiConfiguration config = pairing.first;
+ if (seenFQDNs.add(config.FQDN)) {
+ List<ScanResult> apScanResults = new ArrayList<>();
+
+ List<ScanResult> homeScans =
+ pairing.second.get(WifiManager.PASSPOINT_HOME_NETWORK);
+ List<ScanResult> roamingScans =
+ pairing.second.get(WifiManager.PASSPOINT_ROAMING_NETWORK);
+
+ // TODO(b/118705403): Differentiate home network vs roaming network for summary info
+ if (!CollectionUtils.isEmpty(homeScans)) {
+ apScanResults.addAll(homeScans);
+ } else if (!CollectionUtils.isEmpty(roamingScans)) {
+ apScanResults.addAll(roamingScans);
+ }
+
+ int bestRssi = Integer.MIN_VALUE;
+ for (ScanResult result : apScanResults) {
+ if (result.level >= bestRssi) {
+ bestRssi = result.level;
+ config.SSID = AccessPoint.convertToQuotedString(result.SSID);
+ }
+ }
+
+ AccessPoint accessPoint =
+ getCachedOrCreatePasspoint(apScanResults, accessPointCache, config);
+ accessPoints.add(accessPoint);
+ }
+ }
+ return accessPoints;
+ }
+
+ @VisibleForTesting
+ List<AccessPoint> updateOsuAccessPoints(
+ Map<OsuProvider, List<ScanResult>> providersAndScans,
+ List<AccessPoint> accessPointCache) {
+ List<AccessPoint> accessPoints = new ArrayList<>();
+
+ Set<OsuProvider> alreadyProvisioned = mWifiManager
+ .getMatchingPasspointConfigsForOsuProviders(
+ providersAndScans.keySet()).keySet();
+ for (OsuProvider provider : providersAndScans.keySet()) {
+ if (!alreadyProvisioned.contains(provider)) {
+ AccessPoint accessPointOsu =
+ getCachedOrCreateOsu(providersAndScans.get(provider),
+ accessPointCache, provider);
+ accessPoints.add(accessPointOsu);
+ }
+ }
+ return accessPoints;
+ }
+
+ private AccessPoint getCachedOrCreate(
List<ScanResult> scanResults,
List<AccessPoint> cache) {
AccessPoint accessPoint = getCachedByKey(cache, AccessPoint.getKey(scanResults.get(0)));
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 42eb0b940938..7d227883b1fe 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -48,11 +49,15 @@ import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiNetworkScoreCache;
import android.net.wifi.WifiSsid;
+import android.net.wifi.hotspot2.OsuProvider;
+import android.net.wifi.hotspot2.PasspointConfiguration;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.SystemClock;
import android.provider.Settings;
+import android.util.ArraySet;
+import android.util.Pair;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -74,7 +79,10 @@ import org.mockito.stubbing.Answer;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -94,6 +102,8 @@ public class WifiTrackerTest {
private static final int RSSI_1 = -30;
private static final byte SCORE_1 = 10;
private static final int BADGE_1 = AccessPoint.Speed.MODERATE;
+ private static final String FQDN_1 = "fqdn1";
+ private static final String PROVIDER_FRIENDLY_NAME_1 = "providerFriendlyName1";
private static final String SSID_2 = "ssid2";
private static final String BSSID_2 = "AA:AA:AA:AA:AA:AA";
@@ -102,6 +112,8 @@ public class WifiTrackerTest {
private static final int RSSI_2 = -30;
private static final byte SCORE_2 = 15;
private static final int BADGE_2 = AccessPoint.Speed.FAST;
+ private static final String FQDN_2 = "fqdn2";
+ private static final String PROVIDER_FRIENDLY_NAME_2 = "providerFriendlyName2";
private static final String SSID_3 = "ssid3";
private static final String BSSID_3 = "CC:00:00:00:00:00";
@@ -271,6 +283,61 @@ public class WifiTrackerTest {
0 /* microsecond timestamp */);
}
+ private static WifiConfiguration buildPasspointConfiguration(String fqdn, String friendlyName) {
+ WifiConfiguration config = spy(new WifiConfiguration());
+ config.FQDN = fqdn;
+ config.providerFriendlyName = friendlyName;
+ when(config.isPasspoint()).thenReturn(true);
+ return config;
+ }
+
+ private List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>>
+ createPasspointMatchingWifiConfigsWithDuplicates() {
+ List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> matchingList =
+ new ArrayList<>();
+ Map<Integer, List<ScanResult>> mapping = new HashMap<>();
+
+ mapping.put(WifiManager.PASSPOINT_HOME_NETWORK, Arrays.asList(buildScanResult1()));
+
+ WifiConfiguration passpointConfig1 =
+ buildPasspointConfiguration(FQDN_1, PROVIDER_FRIENDLY_NAME_1);
+ WifiConfiguration passpointConfig2 =
+ buildPasspointConfiguration(FQDN_2, PROVIDER_FRIENDLY_NAME_2);
+
+ matchingList.add(new Pair(passpointConfig1, mapping));
+ matchingList.add(new Pair(passpointConfig1, mapping));
+ matchingList.add(new Pair(passpointConfig2, mapping));
+ matchingList.add(new Pair(passpointConfig2, mapping));
+
+ return matchingList;
+ }
+
+ private List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>>
+ createPasspointMatchingWifiConfigWithScanResults(
+ List<ScanResult> homeList, List<ScanResult> roamingList) {
+ List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> matchingList =
+ new ArrayList<>();
+ Map<Integer, List<ScanResult>> mapping = new HashMap<>();
+
+ if (homeList != null) {
+ mapping.put(WifiManager.PASSPOINT_HOME_NETWORK, homeList);
+ }
+ if (roamingList != null) {
+ mapping.put(WifiManager.PASSPOINT_ROAMING_NETWORK, roamingList);
+ }
+
+ matchingList.add(new Pair(buildPasspointConfiguration(FQDN_1, PROVIDER_FRIENDLY_NAME_1),
+ mapping));
+
+ return matchingList;
+ }
+
+ private static OsuProvider buildOsuProvider(String friendlyName) {
+ Map<String, String> friendlyNames = new HashMap<>();
+ friendlyNames.put("en", friendlyName);
+ return new OsuProvider(null, friendlyNames, null, null, null, null, null);
+ }
+
private WifiTracker createTrackerWithImmediateBroadcastsAndInjectInitialScanResults(
Intent ... intents)
throws InterruptedException {
@@ -926,4 +993,172 @@ public class WifiTrackerTest {
assertThat(tracker.getAccessPoints().get(0).getBssid()).isEqualTo(BSSID_1);
assertThat(tracker.getAccessPoints().get(1).getBssid()).isEqualTo(BSSID_2);
}
+
+ /**
+ * Verifies that updatePasspointAccessPoints will only return AccessPoints whose
+ * isPasspoint() evaluates as true.
+ */
+ @Test
+ public void updatePasspointAccessPoints_returnedAccessPointsArePasspoint() {
+ WifiTracker tracker = createMockedWifiTracker();
+
+ List<AccessPoint> passpointAccessPoints = tracker.updatePasspointAccessPoints(
+ createPasspointMatchingWifiConfigsWithDuplicates(), new ArrayList<>());
+
+ assertTrue(passpointAccessPoints.size() != 0);
+ for (AccessPoint ap : passpointAccessPoints) {
+ assertTrue(ap.isPasspoint());
+ }
+ }
+
+ /**
+ * Verifies that updatePasspointAccessPoints will return the same amount of AccessPoints as
+ * unique WifiConfigurations, even if duplicate FQDNs exist.
+ */
+ @Test
+ public void updatePasspointAccessPoints_ignoresDuplicateFQDNs() {
+ WifiTracker tracker = createMockedWifiTracker();
+
+ // Process matching list of four configs with two duplicate FQDNs.
+ List<AccessPoint> passpointAccessPoints = tracker.updatePasspointAccessPoints(
+ createPasspointMatchingWifiConfigsWithDuplicates(), new ArrayList<>());
+
+ // Should have 2 APs with unique FQDNs, ignoring the 2 duplicate FQDNs.
+ assertThat(passpointAccessPoints).hasSize(2);
+
+ Set<String> fqdns = new ArraySet<>(Arrays.asList(FQDN_1, FQDN_2));
+
+ assertTrue(fqdns.remove(passpointAccessPoints.get(0).getConfig().FQDN));
+ assertTrue(fqdns.remove(passpointAccessPoints.get(1).getConfig().FQDN));
+ }
+
+ /**
+ * Verifies that updatePasspointAccessPoints will return matching cached APs and update their
+ * scan results instead of creating new APs.
+ */
+ @Test
+ public void updatePasspointAccessPoints_usesCachedAccessPoints() {
+ WifiTracker tracker = createMockedWifiTracker();
+
+ ScanResult result = buildScanResult1();
+
+ List<AccessPoint> passpointAccessPointsFirstUpdate = tracker.updatePasspointAccessPoints(
+ createPasspointMatchingWifiConfigWithScanResults(Arrays.asList(result),
+ null), new ArrayList<>());
+ List<AccessPoint> cachedAccessPoints = new ArrayList<>(passpointAccessPointsFirstUpdate);
+
+ int prevRssi = result.level;
+ int newRssi = prevRssi + 10;
+ result.level = newRssi;
+
+ List<AccessPoint> passpointAccessPointsSecondUpdate = tracker.updatePasspointAccessPoints(
+ createPasspointMatchingWifiConfigWithScanResults(Arrays.asList(result),
+ null), cachedAccessPoints);
+
+ // Verify second update AP is the same object as the first update AP
+ assertThat(passpointAccessPointsFirstUpdate.get(0))
+ .isSameAs(passpointAccessPointsSecondUpdate.get(0));
+ // Verify second update AP has the average of the first and second update RSSIs
+ assertThat(passpointAccessPointsSecondUpdate.get(0).getRssi())
+ .isEqualTo((prevRssi + newRssi) / 2);
+ }
+
+ /**
+ * Verifies that updateOsuAccessPoints will only return AccessPoints whose
+ * isOsuProvider() evaluates as true.
+ */
+ @Test
+ public void updateOsuAccessPoints_returnedAccessPointsAreOsuProviders() {
+ WifiTracker tracker = createMockedWifiTracker();
+
+ Map<OsuProvider, List<ScanResult>> providersAndScans = new HashMap<>();
+ providersAndScans.put(
+ buildOsuProvider(PROVIDER_FRIENDLY_NAME_1), Arrays.asList(buildScanResult1()));
+ providersAndScans.put(
+ buildOsuProvider(PROVIDER_FRIENDLY_NAME_2), Arrays.asList(buildScanResult2()));
+
+ List<AccessPoint> osuAccessPoints = tracker.updateOsuAccessPoints(
+ providersAndScans, new ArrayList<>());
+
+ assertThat(osuAccessPoints).hasSize(2);
+ for (AccessPoint ap: osuAccessPoints) {
+ assertThat(ap.isOsuProvider()).isTrue();
+ }
+ }
+
+ /**
+ * Verifies that updateOsuAccessPoints will not return Osu AccessPoints for already provisioned
+ * networks
+ */
+ @Test
+ public void updateOsuAccessPoints_doesNotReturnAlreadyProvisionedOsuAccessPoints() {
+ WifiTracker tracker = createMockedWifiTracker();
+
+ // Start with two Osu Providers
+ Map<OsuProvider, List<ScanResult>> providersAndScans = new HashMap<>();
+ providersAndScans.put(
+ buildOsuProvider(PROVIDER_FRIENDLY_NAME_1), Arrays.asList(buildScanResult1()));
+ providersAndScans.put(
+ buildOsuProvider(PROVIDER_FRIENDLY_NAME_2), Arrays.asList(buildScanResult2()));
+
+ // First update
+ List<AccessPoint> osuAccessPoints = tracker.updateOsuAccessPoints(
+ providersAndScans, new ArrayList<>());
+
+ // Make sure both Osu Providers' APs are returned
+ assertThat(osuAccessPoints).hasSize(2);
+ List<String> friendlyNames = Arrays.asList(
+ osuAccessPoints.get(0).getTitle(), osuAccessPoints.get(1).getTitle());
+ assertThat(friendlyNames)
+ .containsExactly(PROVIDER_FRIENDLY_NAME_1, PROVIDER_FRIENDLY_NAME_2);
+
+ // Simulate Osu Provider 1 being provisioned
+ Map<OsuProvider, PasspointConfiguration> matchingPasspointConfigForOsuProvider =
+ new HashMap<>();
+ matchingPasspointConfigForOsuProvider.put(buildOsuProvider(PROVIDER_FRIENDLY_NAME_1), null);
+ when(mockWifiManager.getMatchingPasspointConfigsForOsuProviders(any())).thenReturn(
+ matchingPasspointConfigForOsuProvider);
+
+ // Second update
+ osuAccessPoints = tracker.updateOsuAccessPoints(
+ providersAndScans, new ArrayList<>());
+
+ // Returned AP should only be for Osu Provider 2
+ assertThat(osuAccessPoints).hasSize(1);
+ assertThat(osuAccessPoints.get(0).getTitle()).isEqualTo(PROVIDER_FRIENDLY_NAME_2);
+ }
+
+ /**
+ * Verifies that updateOsuAccessPoints will return matching cached APs and update their
+ * scan results instead of creating new APs.
+ */
+ @Test
+ public void updateOsuAccessPoints_usesCachedAccessPoints() {
+ WifiTracker tracker = createMockedWifiTracker();
+
+ ScanResult result = buildScanResult1();
+
+ Map<OsuProvider, List<ScanResult>> providersAndScans = new HashMap<>();
+ providersAndScans.put(
+ buildOsuProvider(PROVIDER_FRIENDLY_NAME_1), Arrays.asList(result));
+
+ List<AccessPoint> osuAccessPointsFirstUpdate = tracker.updateOsuAccessPoints(
+ providersAndScans, new ArrayList<>());
+ List<AccessPoint> cachedAccessPoints = new ArrayList<>(osuAccessPointsFirstUpdate);
+
+ // New RSSI for second update
+ int prevRssi = result.level;
+ int newRssi = prevRssi + 10;
+ result.level = newRssi;
+
+ List<AccessPoint> osuAccessPointsSecondUpdate = tracker.updateOsuAccessPoints(
+ providersAndScans, cachedAccessPoints);
+
+ // Verify second update AP is the same object as the first update AP
+ assertTrue(osuAccessPointsFirstUpdate.get(0)
+ == osuAccessPointsSecondUpdate.get(0));
+ // Verify second update AP has the average of the first and second update RSSIs
+ assertThat(osuAccessPointsSecondUpdate.get(0).getRssi())
+ .isEqualTo((prevRssi + newRssi) / 2);
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java
index b8a143a376fd..c5f54bb0f0d9 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataLoaderTest.java
@@ -46,6 +46,7 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.util.ReflectionHelpers;
import java.time.ZonedDateTime;
+import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -99,6 +100,20 @@ public class NetworkCycleDataLoaderTest {
}
@Test
+ public void loadInBackground_hasCyclePeriod_shouldLoadDataForSpecificCycles() {
+ mLoader = spy(new NetworkCycleDataTestLoader(mContext));
+ doNothing().when(mLoader).loadDataForSpecificCycles();
+ final ArrayList<Long> cycles = new ArrayList<>();
+ cycles.add(67890L);
+ cycles.add(12345L);
+ ReflectionHelpers.setField(mLoader, "mCycles", cycles);
+
+ mLoader.loadInBackground();
+
+ verify(mLoader).loadDataForSpecificCycles();
+ }
+
+ @Test
public void loadPolicyData_shouldRecordUsageFromPolicyCycle() {
final int networkType = ConnectivityManager.TYPE_MOBILE;
final String subId = "TestSubscriber";
@@ -139,6 +154,27 @@ public class NetworkCycleDataLoaderTest {
verify(mLoader).recordUsage(fourWeeksAgo, now);
}
+ @Test
+ public void loadDataForSpecificCycles_shouldRecordUsageForSpecifiedTime() {
+ mLoader = spy(new NetworkCycleDataTestLoader(mContext));
+ final long now = System.currentTimeMillis();
+ final long tenDaysAgo = now - (DateUtils.DAY_IN_MILLIS * 10);
+ final long twentyDaysAgo = now - (DateUtils.DAY_IN_MILLIS * 20);
+ final long thirtyDaysAgo = now - (DateUtils.DAY_IN_MILLIS * 30);
+ final ArrayList<Long> cycles = new ArrayList<>();
+ cycles.add(now);
+ cycles.add(tenDaysAgo);
+ cycles.add(twentyDaysAgo);
+ cycles.add(thirtyDaysAgo);
+ ReflectionHelpers.setField(mLoader, "mCycles", cycles);
+
+ mLoader.loadDataForSpecificCycles();
+
+ verify(mLoader).recordUsage(tenDaysAgo, now);
+ verify(mLoader).recordUsage(twentyDaysAgo, tenDaysAgo);
+ verify(mLoader).recordUsage(thirtyDaysAgo, twentyDaysAgo);
+ }
+
public class NetworkCycleDataTestLoader extends NetworkCycleDataLoader<List<NetworkCycleData>> {
private NetworkCycleDataTestLoader(Context context) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 6152b8cbd562..db4b131a0f6f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -698,6 +698,9 @@ class SettingsProtoDumpUtil {
Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST,
GlobalSettingsProto.Gpu.ANGLE_WHITELIST);
dumpSetting(s, p,
+ Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX,
+ GlobalSettingsProto.Gpu.SHOW_ANGLE_IN_USE_DIALOG);
+ dumpSetting(s, p,
Settings.Global.GPU_DEBUG_LAYER_APP,
GlobalSettingsProto.Gpu.DEBUG_LAYER_APP);
dumpSetting(s, p,
@@ -718,6 +721,9 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Global.GAME_DRIVER_WHITELIST,
GlobalSettingsProto.Gpu.GAME_DRIVER_WHITELIST);
+ dumpSetting(s, p,
+ Settings.Global.GAME_DRIVER_BLACKLISTS,
+ GlobalSettingsProto.Gpu.GAME_DRIVER_BLACKLISTS);
p.end(gpuToken);
final long hdmiToken = p.start(GlobalSettingsProto.HDMI);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index e8c728d358ea..0da3b10778e9 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -82,6 +82,7 @@
<uses-permission android:name="android.permission.MOVE_PACKAGE" />
<uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
<uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
+ <uses-permission android:name="android.permission.ACCESS_INSTANT_APPS" />
<uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
<uses-permission android:name="android.permission.MANAGE_ROLLBACKS" />
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
index ac6904300f71..38bf77d5eb0e 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
@@ -55,9 +55,16 @@ public interface ClockPlugin extends Plugin {
void setTextColor(int color);
/**
+ * Sets the color palette for the clock face.
+ * @param supportsDarkText Whether dark text can be displayed.
+ * @param colors Colors that should be used on the clock face, ordered from darker to lighter.
+ */
+ default void setColorPalette(boolean supportsDarkText, int[] colors) {}
+
+ /**
* Notifies that time tick alarm from doze service fired.
*/
- default void dozeTimeTick() { }
+ default void dozeTimeTick() {}
/**
* Set the amount (ratio) that the device has transitioned to doze.
diff --git a/packages/SystemUI/res-keyguard/layout/bubble_clock.xml b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
index 6f7f39810608..c8dc8e43893c 100644
--- a/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
+++ b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
@@ -19,9 +19,21 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
>
- <include
+ <TextClock
android:id="@+id/digital_clock"
- layout="@layout/text_clock"
+ android:layout_marginLeft="20dp"
+ android:layout_marginTop="72dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|left"
+ android:textSize="44dp"
+ android:letterSpacing="0.05"
+ android:textColor="?attr/wallpaperTextColor"
+ android:singleLine="true"
+ style="@style/widget_big"
+ android:format12Hour="@string/keyguard_widget_12_hours_format"
+ android:format24Hour="@string/keyguard_widget_24_hours_format"
+ android:elegantTextHeight="false"
/>
<com.android.keyguard.clock.ImageClock
android:id="@+id/analog_clock"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
index 51f6a4b92413..dc45b4b51925 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
@@ -28,11 +28,20 @@
android:clipToPadding="false"
android:orientation="vertical"
android:layout_centerHorizontal="true">
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="64dp"
+ android:paddingEnd="64dp"
+ android:visibility="gone"
+ android:textColor="?attr/wallpaperTextColor"
+ android:theme="@style/TextAppearance.Keyguard"
+ />
<view class="com.android.keyguard.KeyguardSliceView$Row"
android:id="@+id/row"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/subtitle_clock_padding"
android:orientation="horizontal"
android:gravity="center"
/>
diff --git a/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml b/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml
index 64b676f55fd6..116a044a7075 100644
--- a/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml
+++ b/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml
@@ -19,9 +19,21 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
>
- <include
+ <TextClock
android:id="@+id/digital_clock"
- layout="@layout/text_clock"
+ android:layout_marginLeft="20dp"
+ android:layout_marginTop="72dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|left"
+ android:textSize="44dp"
+ android:letterSpacing="0.05"
+ android:textColor="?attr/wallpaperTextColor"
+ android:singleLine="true"
+ style="@style/widget_big"
+ android:format12Hour="@string/keyguard_widget_12_hours_format"
+ android:format24Hour="@string/keyguard_widget_24_hours_format"
+ android:elegantTextHeight="false"
/>
<com.android.keyguard.clock.StretchAnalogClock
android:id="@+id/analog_clock"
diff --git a/packages/SystemUI/res-keyguard/layout/text_clock.xml b/packages/SystemUI/res-keyguard/layout/text_clock.xml
index b61ad9c4fc11..9f7ea0d44357 100644
--- a/packages/SystemUI/res-keyguard/layout/text_clock.xml
+++ b/packages/SystemUI/res-keyguard/layout/text_clock.xml
@@ -16,9 +16,10 @@
-->
<TextClock
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal"
android:letterSpacing="0.03"
android:textColor="?attr/wallpaperTextColor"
android:singleLine="true"
diff --git a/packages/SystemUI/res-keyguard/values-af/strings.xml b/packages/SystemUI/res-keyguard/values-af/strings.xml
index da11db39bd02..54537e5ee7a2 100644
--- a/packages/SystemUI/res-keyguard/values-af/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-af/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM is nou gedeaktiveer. Voer PUK-kode in om voort te gaan. Jy het <xliff:g id="_NUMBER_1">%d</xliff:g> pogings oor voordat die SIM permanent onbruikbaar word. Kontak die diensverskaffer vir besonderhede.</item>
<item quantity="one">SIM is nou gedeaktiveer. Voer PUK-kode in om voort te gaan. Jy het <xliff:g id="_NUMBER_0">%d</xliff:g> poging oor voordat die SIM permanent onbruikbaar word. Kontak die diensverskaffer vir besonderhede.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Dit is"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Twaalf"</item>
<item msgid="7389464214252023751">"Een"</item>
diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml
index 0d154f552e19..379838dc2a61 100644
--- a/packages/SystemUI/res-keyguard/values-am/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-am/strings.xml
@@ -150,7 +150,7 @@
<item quantity="one">ሲም አሁን ተሰናክሏል። ለመቀጠል የPUK ኮድ ያስገቡ። ሲም እስከመጨረሻው መጠቀም የማይቻል ከመሆኑ በፊት <xliff:g id="_NUMBER_1">%d</xliff:g> ሙከራዎች ይቀረዎታል። ዝርዝሮችን ለማግኘት የአገልግሎት አቅራቢን ያነጋግሩ።</item>
<item quantity="other">ሲም አሁን ተሰናክሏል። ለመቀጠል የPUK ኮድ ያስገቡ። ሲም እስከመጨረሻው መጠቀም የማይቻል ከመሆኑ በፊት <xliff:g id="_NUMBER_1">%d</xliff:g> ሙከራዎች ይቀረዎታል። ዝርዝሮችን ለማግኘት የአገልግሎት አቅራቢን ያነጋግሩ።</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"ነው"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"አስራ ሁለት"</item>
<item msgid="7389464214252023751">"አንድ"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml
index 826f2f05f2ad..2fef0270b15c 100644
--- a/packages/SystemUI/res-keyguard/values-ar/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml
@@ -182,7 +182,7 @@
<item quantity="other">‏تم إيقاف شريحة SIM الآن. أدخل رمز PUK للمتابعة، وتتبقى لديك <xliff:g id="_NUMBER_1">%d</xliff:g> محاولة قبل أن تصبح شريحة SIM غير صالحة للاستخدام نهائيًا. ويمكنك الاتصال بمشغل شبكة الجوّال لمعرفة التفاصيل.</item>
<item quantity="one">‏تم إيقاف شريحة SIM الآن. أدخل رمز PUK للمتابعة، وتتبقى لديك محاولة واحدة (<xliff:g id="_NUMBER_0">%d</xliff:g>) قبل أن تصبح شريحة SIM غير صالحة للاستخدام نهائيًا. ويمكنك الاتصال بمشغل شبكة الجوّال لمعرفة التفاصيل.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"الساعة"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"الثانية عشرة"</item>
<item msgid="7389464214252023751">"الواحدة"</item>
diff --git a/packages/SystemUI/res-keyguard/values-as/strings.xml b/packages/SystemUI/res-keyguard/values-as/strings.xml
index f67e009ca58e..63d0512ca870 100644
--- a/packages/SystemUI/res-keyguard/values-as/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-as/strings.xml
@@ -150,7 +150,7 @@
<item quantity="one">ছিমখন অক্ষম হ’ল। অব্যাহত ৰাখিবলৈ PUK দিয়ক। ছিমখন স্থায়ীভাৱে ব্যৱহাৰৰ অনুপযোগী হোৱাৰ পূৰ্বে আপোনাৰ হাতত <xliff:g id="_NUMBER_1">%d</xliff:g>টা প্ৰয়াস বাকী আছে। সবিশেষ জানিবলৈ বাহকৰ সৈতে যোগাযোগ কৰক।</item>
<item quantity="other">ছিমখন অক্ষম হ’ল। অব্যাহত ৰাখিবলৈ PUK দিয়ক। ছিমখন স্থায়ীভাৱে ব্যৱহাৰৰ অনুপযোগী হোৱাৰ পূৰ্বে আপোনাৰ হাতত <xliff:g id="_NUMBER_1">%d</xliff:g>টা প্ৰয়াস বাকী আছে। সবিশেষ জানিবলৈ বাহকৰ সৈতে যোগাযোগ কৰক।</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"সময়"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"বাৰ"</item>
<item msgid="7389464214252023751">"এক"</item>
diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml
index 50f1b1f3d7bc..3714ec6e98ca 100644
--- a/packages/SystemUI/res-keyguard/values-az/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-az/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM indi deaktivdir. Davam etmək üçün PUK kodunu daxil edin. SIM birdəfəlik yararsız olmadan öncə <xliff:g id="_NUMBER_1">%d</xliff:g> cəhdiniz qalır. Ətraflı məlumat üçün operatorla əlaqə saxlayın.</item>
<item quantity="one">SIM indi deaktivdir. Davam etmək üçün PUK kodunu daxil edin. SIM birdəfəlik yararsız olmadan öncə <xliff:g id="_NUMBER_0">%d</xliff:g> cəhdiniz qalır. Ətraflı məlumat üçün operatorla əlaqə saxlayın.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Saat"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"On iki"</item>
<item msgid="7389464214252023751">"Bir"</item>
diff --git a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
index a5fceef4f97b..327231305c3c 100644
--- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
@@ -158,7 +158,7 @@
<item quantity="few">SIM je sada onemogućen. Unesite PUK kôd da biste nastavili. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja pre nego što SIM postane trajno neupotrebljiv. Detaljne informacije potražite od mobilnog operatera.</item>
<item quantity="other">SIM je sada onemogućen. Unesite PUK kôd da biste nastavili. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja pre nego što SIM postane trajno neupotrebljiv. Detaljne informacije potražite od mobilnog operatera.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Sada je"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"dvanaest"</item>
<item msgid="7389464214252023751">"jedan"</item>
diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml
index 872cd7b997cd..aaa4cb65d37d 100644
--- a/packages/SystemUI/res-keyguard/values-be/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-be/strings.xml
@@ -166,7 +166,7 @@
<item quantity="many">SIM-карта заблакіравана. Каб працягнуць, увядзіце PUK-код. У вас ёсць яшчэ <xliff:g id="_NUMBER_1">%d</xliff:g> спроб, пасля чаго SIM-карта будзе заблакіравана назаўсёды. Звярніцеся да аператара, каб даведацца больш.</item>
<item quantity="other">SIM-карта заблакіравана. Каб працягнуць, увядзіце PUK-код. У вас ёсць яшчэ <xliff:g id="_NUMBER_1">%d</xliff:g> спробы, пасля чаго SIM-карта будзе заблакіравана назаўсёды. Звярніцеся да аператара, каб даведацца больш.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Зараз"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Дванаццаць"</item>
<item msgid="7389464214252023751">"Адна"</item>
diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml
index 741834feca3c..d89dd41c0f72 100644
--- a/packages/SystemUI/res-keyguard/values-bg/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bg/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM картата вече е деактивирана. Въведете PUK кода, за да продължите. Остават ви <xliff:g id="_NUMBER_1">%d</xliff:g> опита, преди SIM картата да стане неизползваема завинаги. Свържете се с оператора за подробности.</item>
<item quantity="one">SIM картата вече е деактивирана. Въведете PUK кода, за да продължите. Остава ви <xliff:g id="_NUMBER_0">%d</xliff:g> опит, преди SIM картата да стане неизползваема завинаги. Свържете се с оператора за подробности.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Часът е"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"дванайсет"</item>
<item msgid="7389464214252023751">"един"</item>
diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml
index 25346a53a049..d0794c3e2995 100644
--- a/packages/SystemUI/res-keyguard/values-bn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml
@@ -150,7 +150,7 @@
<item quantity="one">সিম অক্ষম করা হয়েছে। চালিয়ে যেতে PUK কোড লিখুন। আপনি আর <xliff:g id="_NUMBER_1">%d</xliff:g> বার চেষ্টা করতে পারবেন, তারপরে এই সিমটি আর একেবারেই ব্যবহার করা যাবে না। বিশদে জানতে পরিষেবা প্রদানকারীর সাথে যোগাযোগ করুন।</item>
<item quantity="other">সিম অক্ষম করা হয়েছে। চালিয়ে যেতে PUK কোড লিখুন। আপনি আর <xliff:g id="_NUMBER_1">%d</xliff:g> বার চেষ্টা করতে পারবেন, তারপরে এই সিমটি আর একেবারেই ব্যবহার করা যাবে না। বিশদে জানতে পরিষেবা প্রদানকারীর সাথে যোগাযোগ করুন।</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"এখন"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"বারো"</item>
<item msgid="7389464214252023751">"এক"</item>
diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml
index 9396ef1ff411..72e4603ba8db 100644
--- a/packages/SystemUI/res-keyguard/values-bs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml
@@ -158,7 +158,7 @@
<item quantity="few">SIM kartica je onemogućena. Unesite PUK kôd da nastavite. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva. Za više informacija kontaktirajte mobilnog operatera.</item>
<item quantity="other">SIM kartica je onemogućena. Unesite PUK kôd da nastavite. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva. Za više informacija kontaktirajte mobilnog operatera.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Sada je"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Dvanaest"</item>
<item msgid="7389464214252023751">"Jedan"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml
index 2fa08975cd8a..185a3f3e39ed 100644
--- a/packages/SystemUI/res-keyguard/values-ca/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">La targeta SIM s\'ha desactivat. Introdueix el codi PUK per continuar. Et queden <xliff:g id="_NUMBER_1">%d</xliff:g> intents; si no l\'encertes, la SIM no es podrà tornar a fer servir. Contacta amb l\'operador de telefonia mòbil per obtenir-ne més informació.</item>
<item quantity="one">La targeta SIM s\'ha desactivat. Introdueix el codi PUK per continuar. Et queda <xliff:g id="_NUMBER_0">%d</xliff:g> intent; si no l\'encertes, la SIM no es podrà tornar a fer servir. Contacta amb l\'operador de telefonia mòbil per obtenir-ne més informació.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Són les"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"i dotze"</item>
<item msgid="7389464214252023751">"Una"</item>
diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml
index 2708f8f439f8..bb01b7e91852 100644
--- a/packages/SystemUI/res-keyguard/values-cs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml
@@ -166,7 +166,7 @@
<item quantity="other">SIM karta je teď zablokována. Chcete-li pokračovat, zadejte kód PUK. Máte ještě <xliff:g id="_NUMBER_1">%d</xliff:g> pokusů, poté bude SIM karta natrvalo zablokována. Podrobnosti vám poskytne operátor.</item>
<item quantity="one">SIM karta je teď zablokována. Chcete-li pokračovat, zadejte kód PUK. Máte ještě <xliff:g id="_NUMBER_0">%d</xliff:g> pokus, poté bude SIM karta natrvalo zablokována. Podrobnosti vám poskytne operátor.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Je"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Dvanáct"</item>
<item msgid="7389464214252023751">"Jedna"</item>
diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml
index 34c248d5c6f6..fbdaf0f5eb7e 100644
--- a/packages/SystemUI/res-keyguard/values-da/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-da/strings.xml
@@ -150,7 +150,7 @@
<item quantity="one">SIM-kortet er nu deaktiveret. Angiv PUK-koden for at fortsætte. Du har <xliff:g id="_NUMBER_1">%d</xliff:g> forsøg tilbage, før SIM-kortet bliver permanent ubrugeligt. Kontakt dit mobilselskab for at få flere oplysninger.</item>
<item quantity="other">SIM-kortet er nu deaktiveret. Angiv PUK-koden for at fortsætte. Du har <xliff:g id="_NUMBER_1">%d</xliff:g> forsøg tilbage, før SIM-kortet bliver permanent ubrugeligt. Kontakt dit mobilselskab for at få flere oplysninger.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Den er"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Tolv"</item>
<item msgid="7389464214252023751">"Et"</item>
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index d8daf83f34d9..b6127df02f1d 100644
--- a/packages/SystemUI/res-keyguard/values-de/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-de/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">Die SIM-Karte ist jetzt deaktiviert. Gib den PUK-Code ein, um fortzufahren. Du hast noch <xliff:g id="_NUMBER_1">%d</xliff:g> Versuche, bevor die SIM-Karte endgültig gesperrt wird. Weitere Informationen erhältst du von deinem Mobilfunkanbieter.</item>
<item quantity="one">Die SIM-Karte ist jetzt deaktiviert. Gib den PUK-Code ein, um fortzufahren. Du hast noch <xliff:g id="_NUMBER_0">%d</xliff:g> Versuch, bevor die SIM-Karte endgültig gesperrt wird. Weitere Informationen erhältst du von deinem Mobilfunkanbieter.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Es ist"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"zwölf Uhr"</item>
<item msgid="7389464214252023751">"ein Uhr"</item>
diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml
index 6c0916c1d912..402e29765a3a 100644
--- a/packages/SystemUI/res-keyguard/values-el/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-el/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">Η κάρτα SIM απενεργοποιήθηκε. Καταχωρίστε τον κωδικό PUK, για να συνεχίσετε. Απομένουν <xliff:g id="_NUMBER_1">%d</xliff:g> ακόμη προσπάθειες προτού να μην είναι πλέον δυνατή η χρήση της κάρτας SIM. Επικοινωνήστε με την εταιρεία κινητής τηλεφωνίας για λεπτομέρειες.</item>
<item quantity="one">Η κάρτα SIM απενεργοποιήθηκε. Καταχωρίστε τον κωδικό PUK, για να συνεχίσετε. Απομένει <xliff:g id="_NUMBER_0">%d</xliff:g> ακόμη προσπάθεια προτού να μην είναι πλέον δυνατή η χρήση της κάρτας SIM. Επικοινωνήστε με την εταιρεία κινητής τηλεφωνίας για λεπτομέρειες.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Είναι"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Δώδεκα"</item>
<item msgid="7389464214252023751">"Μία"</item>
diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
index 80c9b82e984a..72b8085c9da3 100644
--- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact operator for details.</item>
<item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_0">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact operator for details.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"It’s"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Twelve"</item>
<item msgid="7389464214252023751">"One"</item>
diff --git a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
index 20c4d56bf2eb..ecc0f71ffcd5 100644
--- a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact operator for details.</item>
<item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_0">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact operator for details.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"It’s"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Twelve"</item>
<item msgid="7389464214252023751">"One"</item>
diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
index 80c9b82e984a..72b8085c9da3 100644
--- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact operator for details.</item>
<item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_0">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact operator for details.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"It’s"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Twelve"</item>
<item msgid="7389464214252023751">"One"</item>
diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
index 80c9b82e984a..72b8085c9da3 100644
--- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact operator for details.</item>
<item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_0">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact operator for details.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"It’s"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Twelve"</item>
<item msgid="7389464214252023751">"One"</item>
diff --git a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
index a33d81741256..501dcb755b57 100644
--- a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‎‎‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎‎‎‏‏‎‏‎‎‎‎‎SIM is now disabled. Enter PUK code to continue. You have ‎‏‎‎‏‏‎<xliff:g id="_NUMBER_1">%d</xliff:g>‎‏‎‎‏‏‏‎ remaining attempts before SIM becomes permanently unusable. Contact carrier for details.‎‏‎‎‏‎</item>
<item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‎‎‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎‎‎‏‏‎‏‎‎‎‎‎SIM is now disabled. Enter PUK code to continue. You have ‎‏‎‎‏‏‎<xliff:g id="_NUMBER_0">%d</xliff:g>‎‏‎‎‏‏‏‎ remaining attempt before SIM becomes permanently unusable. Contact carrier for details.‎‏‎‎‏‎</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‏‎‏‏‎‏‎‎‏‏‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‏‏‏‎‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎‎‎‎‎‏‎‏‎‎‎It’s‎‏‎‎‏‎"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‎‎‎‏‎‏‎‎‎‏‎‏‎‏‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‎‏‏‏‏‎‏‏‎‎Twelve‎‏‎‎‏‎"</item>
<item msgid="7389464214252023751">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‏‏‎‎‏‎‏‎‎‏‏‎‏‎‎‎‏‏‎‏‎‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎One‎‏‎‎‏‎"</item>
diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
index 98453a7c2a79..f93d93305621 100644
--- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">Se inhabilitó la SIM. Para continuar, ingresa el código PUK. Te quedan <xliff:g id="_NUMBER_1">%d</xliff:g> intentos más antes de que la SIM quede inutilizable permanentemente. Comunícate con tu proveedor para obtener más detalles.</item>
<item quantity="one">Se inhabilitó la SIM. Para continuar, ingresa el código PUK. Te queda <xliff:g id="_NUMBER_0">%d</xliff:g> intento más antes de que la SIM quede inutilizable permanentemente. Comunícate con tu proveedor para obtener más detalles.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Son las"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Doce"</item>
<item msgid="7389464214252023751">"Una"</item>
diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml
index 00bdd913a582..9c189d9f1245 100644
--- a/packages/SystemUI/res-keyguard/values-es/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">La tarjeta SIM está inhabilitada. Introduce el código PUK para continuar. Te quedan <xliff:g id="_NUMBER_1">%d</xliff:g> intentos para que la tarjeta SIM quede inservible de forma permanente. Ponte en contacto con tu operador para obtener más información.</item>
<item quantity="one">La tarjeta SIM está inhabilitada. Introduce el código PUK para continuar. Te queda <xliff:g id="_NUMBER_0">%d</xliff:g> intento para que la tarjeta SIM quede inservible de forma permanente. Ponte en contacto con tu operador para obtener más información.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Son las"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Doce"</item>
<item msgid="7389464214252023751">"Uno"</item>
diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml
index e77880403b79..759453732db9 100644
--- a/packages/SystemUI/res-keyguard/values-et/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-et/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM-kaart on nüüd keelatud. Jätkamiseks sisestage PUK-kood. Teil on jäänud veel <xliff:g id="_NUMBER_1">%d</xliff:g> katset enne, kui SIM-kaart püsivalt lukustatakse. Lisateavet küsige operaatorilt.</item>
<item quantity="one">SIM-kaart on nüüd keelatud. Jätkamiseks sisestage PUK-kood. Teil on jäänud veel <xliff:g id="_NUMBER_0">%d</xliff:g> katse enne, kui SIM-kaart püsivalt lukustatakse. Lisateavet küsige operaatorilt.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Kell on"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Kaksteist"</item>
<item msgid="7389464214252023751">"Üks"</item>
diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml
index 3ebb536d0394..8b1284d7c535 100644
--- a/packages/SystemUI/res-keyguard/values-eu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">Desgaitu egin da SIM txartela. Aurrera egiteko, idatzi PUK kodea. <xliff:g id="_NUMBER_1">%d</xliff:g> saiakera geratzen zaizkizu SIM txartela betiko erabilgaitz geratu aurretik. Xehetasunak lortzeko, jarri operadorearekin harremanetan.</item>
<item quantity="one">Desgaitu egin da SIM txartela. Aurrera egiteko, idatzi PUK kodea. <xliff:g id="_NUMBER_0">%d</xliff:g> saiakera geratzen zaizu SIM txartela betiko erabilgaitz geratu aurretik. Xehetasunak lortzeko, jarri operadorearekin harremanetan.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Ordua:"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Hamabiak"</item>
<item msgid="7389464214252023751">"Ordu bata"</item>
diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml
index 0c30d03cc14c..183152e37ff8 100644
--- a/packages/SystemUI/res-keyguard/values-fa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml
@@ -150,7 +150,7 @@
<item quantity="one">‏سیم‌کارت اکنون غیرفعال است. برای ادامه دادن کد PUK را وارد کنید. <xliff:g id="_NUMBER_1">%d</xliff:g> تلاش دیگر باقی مانده است و پس از آن سیم‌کارت برای همیشه غیرقابل‌استفاده می‌شود. برای اطلاع از جزئیات با شرکت مخابراتی تماس بگیرید.</item>
<item quantity="other">‏سیم‌کارت اکنون غیرفعال است. برای ادامه دادن کد PUK را وارد کنید. <xliff:g id="_NUMBER_1">%d</xliff:g> تلاش دیگر باقی مانده است و پس از آن سیم‌کارت برای همیشه غیرقابل‌استفاده می‌شود. برای اطلاع از جزئیات با شرکت مخابراتی تماس بگیرید.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"ساعت:"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"دوازده"</item>
<item msgid="7389464214252023751">"یک"</item>
diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml
index 60923722fa56..ec3c596f31bf 100644
--- a/packages/SystemUI/res-keyguard/values-fi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM-kortti on nyt lukittu. Anna PUK-koodi, niin voit jatkaa. Sinulla on <xliff:g id="_NUMBER_1">%d</xliff:g> yritystä jäljellä, ennen kuin SIM-kortti poistuu pysyvästi käytöstä. Pyydä lisätietoja operaattoriltasi.</item>
<item quantity="one">SIM-kortti on nyt lukittu. Anna PUK-koodi, niin voit jatkaa. Sinulla on <xliff:g id="_NUMBER_0">%d</xliff:g> yritys jäljellä, ennen kuin SIM-kortti poistuu pysyvästi käytöstä. Pyydä lisätietoja operaattoriltasi.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Kello on"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Kaksitoista"</item>
<item msgid="7389464214252023751">"Yksi"</item>
diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
index 8e92ffc91db6..73705c876091 100644
--- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
@@ -150,7 +150,7 @@
<item quantity="one">La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste <xliff:g id="_NUMBER_1">%d</xliff:g> tentative avant que votre carte SIM devienne définitivement inutilisable. Pour obtenir plus de détails, communiquez avec votre fournisseur de services.</item>
<item quantity="other">La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste <xliff:g id="_NUMBER_1">%d</xliff:g> tentatives avant que votre carte SIM devienne définitivement inutilisable. Pour obtenir plus de détails, communiquez avec votre fournisseur de services.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Il est"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"douze h."</item>
<item msgid="7389464214252023751">"Une h."</item>
diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml
index cde5e682224f..cf4f2d001d83 100644
--- a/packages/SystemUI/res-keyguard/values-fr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml
@@ -150,7 +150,7 @@
<item quantity="one">La carte SIM est maintenant désactivée. Saisissez le code PUK pour continuer. Il vous reste <xliff:g id="_NUMBER_1">%d</xliff:g> tentative avant que votre carte SIM ne devienne définitivement inutilisable. Pour de plus amples informations, veuillez contacter votre opérateur.</item>
<item quantity="other">La carte SIM est maintenant désactivée. Saisissez le code PUK pour continuer. Il vous reste <xliff:g id="_NUMBER_1">%d</xliff:g> tentatives avant que votre carte SIM ne devienne définitivement inutilisable. Pour de plus amples informations, veuillez contacter votre opérateur.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Il est"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"douze heures"</item>
<item msgid="7389464214252023751">"une heure"</item>
diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index 6d85cdba5ce3..810a75ba034b 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">A SIM está desactivada. Introduce o código PUK para continuar. Quédanche <xliff:g id="_NUMBER_1">%d</xliff:g> intentos antes de que a SIM quede inutilizable para sempre. Contacta co operador para obter información.</item>
<item quantity="one">A SIM está desactivada. Introduce o código PUK para continuar. Quédache <xliff:g id="_NUMBER_0">%d</xliff:g> intento antes de que a SIM quede inutilizable para sempre. Contacta co operador para obter información.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Hora:"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Doce"</item>
<item msgid="7389464214252023751">"Unha"</item>
diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml
index d9fdf03d4a17..538b10081a83 100644
--- a/packages/SystemUI/res-keyguard/values-gu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml
@@ -150,7 +150,7 @@
<item quantity="one">સિમ હવે બંધ કરેલ છે. ચાલુ રાખવા માટે PUK કોડ દાખલ કરો. સિમ કાયમીરૂપે બિનઉપયોગી બની જાય એ પહેલાં તમારી પાસે <xliff:g id="_NUMBER_1">%d</xliff:g> પ્રયાસ બાકી છે. વિગતો માટે કૅરિઅરનો સંપર્ક કરો.</item>
<item quantity="other">સિમ હવે બંધ કરેલ છે. ચાલુ રાખવા માટે PUK કોડ દાખલ કરો. સિમ કાયમીરૂપે બિનઉપયોગી બની જાય એ પહેલાં તમારી પાસે <xliff:g id="_NUMBER_1">%d</xliff:g> પ્રયાસો બાકી છે. વિગતો માટે કૅરિઅરનો સંપર્ક કરો.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"સમય છે"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"બાર"</item>
<item msgid="7389464214252023751">"એક"</item>
diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml
index b004cdec4045..f03ddd44cb3b 100644
--- a/packages/SystemUI/res-keyguard/values-hi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml
@@ -150,7 +150,7 @@
<item quantity="one">सिम बंद कर दिया गया है. जारी रखने के लिए PUK कोड डालें. आपके पास <xliff:g id="_NUMBER_1">%d</xliff:g> मौके बचे हैं, उसके बाद, सिम हमेशा के लिए काम करना बंद कर देगा. जानकारी के लिए, मोबाइल और इंटरनेट सेवा देने वाली कंपनी से संपर्क करें.</item>
<item quantity="other">सिम बंद कर दिया गया है. जारी रखने के लिए PUK कोड डालें. आपके पास <xliff:g id="_NUMBER_1">%d</xliff:g> मौके बचे हैं, उसके बाद, सिम हमेशा के लिए काम करना बंद कर देगा. जानकारी के लिए, मोबाइल और इंटरनेट सेवा देने वाली कंपनी से संपर्क करें.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"यह"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"बारह"</item>
<item msgid="7389464214252023751">"एक"</item>
diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml
index c99b646b7682..28394538d8bb 100644
--- a/packages/SystemUI/res-keyguard/values-hr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hr/strings.xml
@@ -158,7 +158,7 @@
<item quantity="few">SIM je sada onemogućen. Unesite PUK kôd da biste nastavili. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva. Više informacija zatražite od mobilnog operatera.</item>
<item quantity="other">SIM je sada onemogućen. Unesite PUK kôd da biste nastavili. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva. Više informacija zatražite od mobilnog operatera.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Sada je"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Dvanaest"</item>
<item msgid="7389464214252023751">"Jedan"</item>
diff --git a/packages/SystemUI/res-keyguard/values-hu/strings.xml b/packages/SystemUI/res-keyguard/values-hu/strings.xml
index 4eb8bc886d0d..de22c02df0df 100644
--- a/packages/SystemUI/res-keyguard/values-hu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hu/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">A SIM-kártya le van tiltva. A folytatáshoz adja meg a PUK-kódot. Még <xliff:g id="_NUMBER_1">%d</xliff:g> próbálkozása van, mielőtt végleg használhatatlanná válik a SIM-kártya. További információért forduljon a szolgáltatóhoz.</item>
<item quantity="one">A SIM-kártya le van tiltva. A folytatáshoz adja meg a PUK-kódot. Még <xliff:g id="_NUMBER_0">%d</xliff:g> próbálkozása van, mielőtt végleg használhatatlanná válik a SIM-kártya. További információért forduljon a szolgáltatóhoz.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Az idő:"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Tizenkettő"</item>
<item msgid="7389464214252023751">"Egy"</item>
diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml
index 5d9a2c0c3fcf..2c104371faa5 100644
--- a/packages/SystemUI/res-keyguard/values-hy/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml
@@ -150,7 +150,7 @@
<item quantity="one">SIM քարտն անջատված է: Շարունակելու համար մուտքագրեք PUK կոդը: Մնացել է <xliff:g id="_NUMBER_1">%d</xliff:g> փորձ, որից հետո SIM քարտն այլևս հնարավոր չի լինի օգտագործել: Մանրամասների համար դիմեք օպերատորին:</item>
<item quantity="other">SIM քարտն անջատված է: Շարունակելու համար մուտքագրեք PUK կոդը: Մնացել է <xliff:g id="_NUMBER_1">%d</xliff:g> փորձ, որից հետո SIM քարտն այլևս հնարավոր չի լինի օգտագործել: Մանրամասների համար դիմեք օպերատորին:</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Ժամն է՝"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"տասներկու"</item>
<item msgid="7389464214252023751">"մեկ"</item>
diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml
index 603b4c25e9d0..0cd138250fad 100644
--- a/packages/SystemUI/res-keyguard/values-in/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-in/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM kini dinonaktifkan. Masukkan kode PUK untuk melanjutkan. Tersisa <xliff:g id="_NUMBER_1">%d</xliff:g> percobaan sebelum SIM tidak dapat digunakan secara permanen. Hubungi operator untuk mengetahui detailnya.</item>
<item quantity="one">SIM kini dinonaktifkan. Masukkan kode PUK untuk melanjutkan. Tersisa <xliff:g id="_NUMBER_0">%d</xliff:g> percobaan sebelum SIM tidak dapat digunakan secara permanen. Hubungi operator untuk mengetahui detailnya.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Pukul"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Dua Belas"</item>
<item msgid="7389464214252023751">"Satu"</item>
diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml
index 71f2078a6010..dd9785d976a4 100644
--- a/packages/SystemUI/res-keyguard/values-is/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-is/strings.xml
@@ -150,7 +150,7 @@
<item quantity="one">SIM-kortið er nú óvirkt. Sláðu inn PUK-númer til að halda áfram. Það er <xliff:g id="_NUMBER_1">%d</xliff:g> tilraun eftir þar til SIM-kortið verður ónothæft til frambúðar. Hafðu samband við símafyrirtækið til að fá upplýsingar.</item>
<item quantity="other">SIM-kortið er nú óvirkt. Sláðu inn PUK-númer til að halda áfram. Það eru <xliff:g id="_NUMBER_1">%d</xliff:g> tilraunir eftir þar til SIM-kortið verður ónothæft til frambúðar. Hafðu samband við símafyrirtækið til að fá upplýsingar.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Hún er"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Tólf"</item>
<item msgid="7389464214252023751">"Eitt"</item>
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index e0b55b37fe23..ac2375fd8c34 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora <xliff:g id="_NUMBER_1">%d</xliff:g> tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.</item>
<item quantity="one">La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora <xliff:g id="_NUMBER_0">%d</xliff:g> tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Ora"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Dodici"</item>
<item msgid="7389464214252023751">"Una"</item>
diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml
index 509c4637ab92..0fadaffa5c9e 100644
--- a/packages/SystemUI/res-keyguard/values-iw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml
@@ -166,7 +166,7 @@
<item quantity="other">‏כרטיס ה-SIM מושבת כעת. יש להזין קוד PUK כדי להמשיך. נותרו לך <xliff:g id="_NUMBER_1">%d</xliff:g> ניסיונות נוספים לפני שכרטיס ה-SIM ינעל לצמיתות. למידע נוסף, ניתן לפנות לספק שלך.</item>
<item quantity="one">‏כרטיס ה-SIM מושבת כעת. יש להזין קוד PUK כדי להמשיך. נותר לך <xliff:g id="_NUMBER_0">%d</xliff:g> ניסיון נוסף לפני שכרטיס ה-SIM ינעל לצמיתות. למידע נוסף, ניתן לפנות לספק שלך.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"השעה"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"שתים-עשרה"</item>
<item msgid="7389464214252023751">"אחת"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ja/strings.xml b/packages/SystemUI/res-keyguard/values-ja/strings.xml
index 343d557e50c7..b0514ef4d741 100644
--- a/packages/SystemUI/res-keyguard/values-ja/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ja/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM が無効になりました。続行するには PUK コードを入力してください。入力できるのはあと <xliff:g id="_NUMBER_1">%d</xliff:g> 回です。この回数を超えると SIM は完全に使用できなくなります。詳しくは携帯通信会社にお問い合わせください。</item>
<item quantity="one">SIM が無効になりました。続行するには PUK コードを入力してください。入力できるのはあと <xliff:g id="_NUMBER_0">%d</xliff:g> 回です。この回数を超えると SIM は完全に使用できなくなります。詳しくは携帯通信会社にお問い合わせください。</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"時刻:"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"12"</item>
<item msgid="7389464214252023751">"1"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ka/strings.xml b/packages/SystemUI/res-keyguard/values-ka/strings.xml
index 9118e5666d5b..9290874557df 100644
--- a/packages/SystemUI/res-keyguard/values-ka/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ka/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM ბარათი ახლა დეაქტივირებულია. გასაგრძელებლად შეიყვანეთ PUK-კოდი. თქვენ დაგრჩათ <xliff:g id="_NUMBER_1">%d</xliff:g> მცდელობა, სანამ SIM სამუდამოდ გამოუსადეგარი გახდება. დეტალური ინფორმაციისთვის დაუკავშირდით თქვენს ოპერატორს.</item>
<item quantity="one">SIM ბარათი ახლა დეაქტივირებულია. გასაგრძელებლად შეიყვანეთ PUK-კოდი. თქვენ დაგრჩათ <xliff:g id="_NUMBER_0">%d</xliff:g> მცდელობა, სანამ SIM სამუდამოდ გამოუსადეგარი გახდება. დეტალური ინფორმაციისთვის დაუკავშირდით თქვენს ოპერატორს.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"ახლაა"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"თორმეტი"</item>
<item msgid="7389464214252023751">"ერთი"</item>
diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml
index 2270c92da0aa..f1d64499ac45 100644
--- a/packages/SystemUI/res-keyguard/values-kk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM картасы өшірілді. Жалғастыру үшін PUK кодын енгізіңіз. <xliff:g id="_NUMBER_1">%d</xliff:g> мүмкіндік қалды, одан кейін SIM картасы біржола құлыпталады. Толығырақ мәліметті оператордан алыңыз.</item>
<item quantity="one">SIM картасы өшірілді. Жалғастыру үшін PUK кодын енгізіңіз. <xliff:g id="_NUMBER_0">%d</xliff:g> мүмкіндік қалды, одан кейін SIM картасы біржола құлыпталады. Толығырақ мәліметті оператордан алыңыз.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Қазір"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Он екі"</item>
<item msgid="7389464214252023751">"Бір"</item>
diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml
index 80b124ad47de..f4795b6e79dd 100644
--- a/packages/SystemUI/res-keyguard/values-km/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-km/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">ឥឡូវនេះស៊ីមត្រូវបានបិទ។ សូមបញ្ចូលកូដ PUK ដើម្បីបន្ត។ អ្នកនៅសល់ការព្យាយាម <xliff:g id="_NUMBER_1">%d</xliff:g> ដងទៀត​មុនពេល​ស៊ីម​មិនអាច​ប្រើបាន​ជា​អចិន្ត្រៃយ៍។ ទាក់ទង​ទៅ​ក្រុមហ៊ុន​សេវា​ទូរសព្ទ​សម្រាប់ព័ត៌មានលម្អិត។</item>
<item quantity="one">ឥឡូវនេះស៊ីមត្រូវបានបិទ។ សូមបញ្ចូលកូដ PUK ដើម្បីបន្ត។ អ្នកនៅសល់ការព្យាយាម <xliff:g id="_NUMBER_0">%d</xliff:g> ដងទៀតមុនពេលស៊ីមមិនអាចប្រើបានជាអចិន្ត្រៃយ៍។ ទាក់ទង​ទៅ​ក្រុមហ៊ុន​សេវា​ទូរសព្ទ​សម្រាប់​ព័ត៌មាន​លម្អិត។</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"វា​ជា"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"ដប់ពីរ"</item>
<item msgid="7389464214252023751">"មួយ"</item>
diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml
index f48d6060b2a6..6f83dde04176 100644
--- a/packages/SystemUI/res-keyguard/values-kn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml
@@ -150,7 +150,7 @@
<item quantity="one">ಸಿಮ್ ಅನ್ನು ಈಗ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ. ಮುಂದುವರಿಸಲು PUK ಕೋಡ್ ನಮೂದಿಸಿ. ಸಿಮ್ ಶಾಶ್ವತವಾಗಿ ನಿಷ್ಪ್ರಯೋಜಕವಾಗುವ ಮುನ್ನ ನಿಮ್ಮಲ್ಲಿ <xliff:g id="_NUMBER_1">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ. ವಿವರಗಳಿಗಾಗಿ ವಾಹಕವನ್ನು ಸಂಪರ್ಕಿಸಿ.</item>
<item quantity="other">ಸಿಮ್ ಅನ್ನು ಈಗ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ. ಮುಂದುವರಿಸಲು PUK ಕೋಡ್ ನಮೂದಿಸಿ. ಸಿಮ್ ಶಾಶ್ವತವಾಗಿ ನಿಷ್ಪ್ರಯೋಜಕವಾಗುವ ಮುನ್ನ ನಿಮ್ಮಲ್ಲಿ <xliff:g id="_NUMBER_1">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ. ವಿವರಗಳಿಗಾಗಿ ವಾಹಕವನ್ನು ಸಂಪರ್ಕಿಸಿ.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"ಇದು"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"ಹನ್ನೆರಡು"</item>
<item msgid="7389464214252023751">"ಒಂದು"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml
index 046600911eae..1651be742a3d 100644
--- a/packages/SystemUI/res-keyguard/values-ko/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM이 사용 중지되었습니다. 계속하려면 PUK 코드를 입력하세요. <xliff:g id="_NUMBER_1">%d</xliff:g>번 더 실패하면 SIM을 완전히 사용할 수 없게 됩니다. 자세한 내용은 이동통신사에 문의하세요.</item>
<item quantity="one">SIM이 사용 중지되었습니다. 계속하려면 PUK 코드를 입력하세요. <xliff:g id="_NUMBER_0">%d</xliff:g>번 더 실패하면 SIM을 완전히 사용할 수 없게 됩니다. 자세한 내용은 이동통신사에 문의하세요.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"현재 시각:"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"열두 시"</item>
<item msgid="7389464214252023751">"한 시"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml
index eca9b2214b96..6d0f2ff635dd 100644
--- a/packages/SystemUI/res-keyguard/values-ky/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM-карта азыр жарактан чыкты. Улантуу үчүн PUK-кодду киргизиңиз. SIM-картанын биротоло жарактан чыгарына <xliff:g id="_NUMBER_1">%d</xliff:g> аракет калды. Чоо-жайын билүү үчүн байланыш операторуна кайрылыңыз.</item>
<item quantity="one">SIM-карта азыр жарактан чыкты. Улантуу үчүн PUK-кодду киргизиңиз. SIM-картанын биротоло жарактан чыгаарына <xliff:g id="_NUMBER_0">%d</xliff:g> аракет калды. Чоо-жайын билүү үчүн байланыш операторуна кайрылыңыз.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Саат"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Он эки"</item>
<item msgid="7389464214252023751">"Бир"</item>
diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml
index bd6e53df924b..23f179e049d4 100644
--- a/packages/SystemUI/res-keyguard/values-lo/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lo/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">ຕອນນີ້ປິດການນຳໃຊ້ SIM ແລ້ວ. ໃສ່ລະຫັດ PUK ເພື່ອດຳເນີນການຕໍ່. ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="_NUMBER_1">%d</xliff:g> ເທື່ອກ່ອນທີ່ SIM ຈະບໍ່ສາມາດໃຊ້ໄດ້ຖາວອນ. ກະລຸນາຕິດຕໍ່ຜູ້ໃຫ້ບໍລິການສຳລັບລາຍລະອຽດ.</item>
<item quantity="one">ຕອນນີ້ປິດການນຳໃຊ້ SIM ແລ້ວ. ໃສ່ລະຫັດ PUK ເພື່ອດຳເນີນການຕໍ່. ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="_NUMBER_0">%d</xliff:g> ເທື່ອກ່ອນທີ່ SIM ຈະບໍ່ສາມາດໃຊ້ໄດ້ຖາວອນ. ກະລຸນາຕິດຕໍ່ຜູ້ໃຫ້ບໍລິການສຳລັບລາຍລະອຽດ.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"ມັນແມ່ນ"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"ສິບສອງ"</item>
<item msgid="7389464214252023751">"ໜຶ່ງ"</item>
diff --git a/packages/SystemUI/res-keyguard/values-lt/strings.xml b/packages/SystemUI/res-keyguard/values-lt/strings.xml
index 6df93d8d4838..9e4d169129bc 100644
--- a/packages/SystemUI/res-keyguard/values-lt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lt/strings.xml
@@ -166,7 +166,7 @@
<item quantity="many">SIM kortelė dabar yra išjungta. Jei norite tęsti, įveskite PUK kodą. Jums liko <xliff:g id="_NUMBER_1">%d</xliff:g> bandymo. Paskui visiškai nebegalėsite naudoti SIM kortelės. Jei reikia išsamios informacijos, susisiekite su operatoriumi.</item>
<item quantity="other">SIM kortelė dabar yra išjungta. Jei norite tęsti, įveskite PUK kodą. Jums liko <xliff:g id="_NUMBER_1">%d</xliff:g> bandymų. Paskui visiškai nebegalėsite naudoti SIM kortelės. Jei reikia išsamios informacijos, susisiekite su operatoriumi.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Dabar"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Dvylika"</item>
<item msgid="7389464214252023751">"Pirma"</item>
diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml
index d9061763e083..9ea4143f2e6e 100644
--- a/packages/SystemUI/res-keyguard/values-lv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml
@@ -158,7 +158,7 @@
<item quantity="one">SIM karte tagad ir atspējota. Ievadiet PUK kodu, lai turpinātu. Varat mēģināt vēl <xliff:g id="_NUMBER_1">%d</xliff:g> reizi. Kļūdas gadījumā SIM karti vairs nevarēs izmantot. Lai iegūtu detalizētu informāciju, sazinieties ar mobilo sakaru operatoru.</item>
<item quantity="other">SIM karte tagad ir atspējota. Ievadiet PUK kodu, lai turpinātu. Varat mēģināt vēl <xliff:g id="_NUMBER_1">%d</xliff:g> reizes. Kļūdas gadījumā SIM karti vairs nevarēs izmantot. Lai iegūtu detalizētu informāciju, sazinieties ar mobilo sakaru operatoru.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Laiks:"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Divpadsmit"</item>
<item msgid="7389464214252023751">"Viens"</item>
diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml
index 221b99748291..e48b93d4fb46 100644
--- a/packages/SystemUI/res-keyguard/values-mk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml
@@ -150,7 +150,7 @@
<item quantity="one">SIM-картичката сега е оневозможена. Внесете PUK-код за да продолжите. Ви преостанува уште <xliff:g id="_NUMBER_1">%d</xliff:g> обид пред SIM-картичката да стане трајно неупотреблива. Контактирајте го операторот за детали.</item>
<item quantity="other">SIM-картичката сега е оневозможена. Внесете PUK-код за да продолжите. Ви преостануваат уште <xliff:g id="_NUMBER_1">%d</xliff:g> обиди пред SIM-картичката да стане трајно неупотреблива. Контактирајте го операторот за детали.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Сега е"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Дванаесет"</item>
<item msgid="7389464214252023751">"Еден"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml
index e6642884b343..37ce00710b3f 100644
--- a/packages/SystemUI/res-keyguard/values-ml/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">സിം ഇപ്പോൾ പ്രവർത്തനരഹിതമാക്കി. തുടരുന്നതിന് PUK കോഡ് നൽകുക. സിം ശാശ്വതമായി ഉപയോഗശൂന്യമാകുന്നതിന് മുമ്പായി <xliff:g id="_NUMBER_1">%d</xliff:g> ശ്രമങ്ങൾ കൂടി ശേഷിക്കുന്നു. വിശദാംശങ്ങൾക്ക് കാരിയറുമായി ബന്ധപ്പെടുക.</item>
<item quantity="one">സിം ഇപ്പോൾ പ്രവർത്തനരഹിതമാക്കി. തുടരുന്നതിന് PUK കോഡ് നൽകുക. സിം ശാശ്വതമായി ഉപയോഗശൂന്യമാകുന്നതിന് മുമ്പായി <xliff:g id="_NUMBER_0">%d</xliff:g> ശ്രമം കൂടി ശേഷിക്കുന്നു. വിശദാംശങ്ങൾക്ക് കാരിയറുമായി ബന്ധപ്പെടുക.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"സമയം"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"പന്ത്രണ്ട്"</item>
<item msgid="7389464214252023751">"ഒന്ന്"</item>
diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml
index e4187316143a..86da6889249a 100644
--- a/packages/SystemUI/res-keyguard/values-mn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mn/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM-г идэвхгүй болголоо. Үргэлжлүүлэхийн тулд PUK кодыг оруулна уу. Таны SIM бүрмөсөн хүчингүй болох хүртэл <xliff:g id="_NUMBER_1">%d</xliff:g> оролдлого үлдлээ. Дэлгэрэнгүй мэдээлэл авахын тулд оператор компанитайгаа холбогдоно уу.</item>
<item quantity="one">SIM-г идэвхгүй болголоо. Үргэлжлүүлэхийн тулд PUK кодыг оруулна уу. Таны SIM бүрмөсөн хүчингүй болох хүртэл <xliff:g id="_NUMBER_0">%d</xliff:g> оролдлого үлдлээ. Дэлгэрэнгүй мэдээлэл авахын тулд оператор компанитайгаа холбогдоно уу.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Одоо"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Арван хоёр"</item>
<item msgid="7389464214252023751">"Нэг"</item>
diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml
index 9d83e93b5e68..ea0c0bb7737d 100644
--- a/packages/SystemUI/res-keyguard/values-mr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml
@@ -150,7 +150,7 @@
<item quantity="one">सिम आता बंद केलेले आहे. सुरू ठेवण्यासाठी PUK कोड टाका. सिम कायमचे बंद होण्याआधी तुमच्याकडे <xliff:g id="_NUMBER_1">%d</xliff:g> प्रयत्न शिल्लक आहे. तपशीलांसाठी वाहकाशी संपर्क साधा.</item>
<item quantity="other">सिम आता बंद केलेले आहे. सुरू ठेवण्यासाठी PUK कोड टाका. सिम कायमचे बंद होण्याआधी तुमच्याकडे <xliff:g id="_NUMBER_1">%d</xliff:g> प्रयत्न शिल्लक आहेत. तपशीलांसाठी वाहकाशी संपर्क साधा.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"हे आहे"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"बारा"</item>
<item msgid="7389464214252023751">"एक"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml
index 1c82f7c1bda6..03dca91c5d4e 100644
--- a/packages/SystemUI/res-keyguard/values-ms/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ms/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">Kini SIM dilumpuhkan. Masukkan kod PUK untuk meneruskan. Tinggal <xliff:g id="_NUMBER_1">%d</xliff:g> percubaan sebelum SIM tidak boleh digunakan secara kekal. Hubungi pembawa untuk mendapatkan butiran.</item>
<item quantity="one">Kini SIM dilumpuhkan. Masukkan kod PUK untuk meneruskan. Tinggal <xliff:g id="_NUMBER_0">%d</xliff:g> percubaan sebelum SIM tidak boleh digunakan secara kekal. Hubungi pembawa untuk mendapatkan butiran.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Pukul"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Dua bls"</item>
<item msgid="7389464214252023751">"Satu"</item>
diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml
index efdd779beae6..a468a852d787 100644
--- a/packages/SystemUI/res-keyguard/values-my/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-my/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">ဆင်းမ်ကဒ်သည် ယခု ပိတ်သွားပါပြီ။ ရှေ့ဆက်ရန် PUK ကုဒ်ကို ထည့်ပါ။ ဆင်းမ်ကဒ် အပြီးပိတ်မသွားမီ သင့်တွင် <xliff:g id="_NUMBER_1">%d</xliff:g> ကြိမ် စမ်းသပ်ခွင့် ကျန်ပါသေးသည်။ အသေးစိတ်အချက်များအတွက် ဝန်ဆောင်မှုပေးသူကို ဆက်သွယ်ပါ။</item>
<item quantity="one">ဆင်းမ်ကဒ်သည် ယခု ပိတ်သွားပါပြီ။ ရှေ့ဆက်ရန် PUK ကုဒ်ကို ထည့်ပါ။ ဆင်းမ်ကဒ် အပြီးပိတ်မသွားမီ သင့်တွင် <xliff:g id="_NUMBER_0">%d</xliff:g> ကြိမ် စမ်းသပ်ခွင့် ကျန်ပါသေးသည်။ အသေးစိတ်အချက်များအတွက် ဝန်ဆောင်မှုပေးသူကို ဆက်သွယ်ပါ။</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"ယခု"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"ဆယ့်နှစ်"</item>
<item msgid="7389464214252023751">"တစ်"</item>
diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml
index 17704c4402d2..fcf06eb7b543 100644
--- a/packages/SystemUI/res-keyguard/values-nb/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM-kortet er deaktivert nå. Skriv inn PUK-koden for å fortsette. Du har <xliff:g id="_NUMBER_1">%d</xliff:g> forsøk igjen før SIM-kortet blir permanent ubrukelig. Kontakt operatøren for å få vite mer.</item>
<item quantity="one">SIM-kortet er deaktivert nå. Skriv inn PUK-koden for å fortsette. Du har <xliff:g id="_NUMBER_0">%d</xliff:g> forsøk igjen før SIM-kortet blir permanent ubrukelig. Kontakt operatøren for å få vite mer.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Klokken"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Tolv"</item>
<item msgid="7389464214252023751">"Ett"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index 77bc11337672..c3d92ab18a15 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM लाई असक्षम पारिएको छ। जारी राख्न PUK कोड प्रविष्टि गर्नुहोस्। तपाईंसँग <xliff:g id="_NUMBER_1">%d</xliff:g> प्रयासहरू बाँकी छन्, त्यसपछि SIM सदाका लागि प्रयोग गर्न नमिल्ने हुन्छ। विवरणहरूका लागि सेवा प्रदायकलाई सम्पर्क गर्नुहोस्।</item>
<item quantity="one">SIM लाई असक्षम पारिएको छ। जारी राख्न PUK कोड प्रविष्टि गर्नुहोस्। तपाईंसँग <xliff:g id="_NUMBER_0">%d</xliff:g> प्रयास बाँकी छ, त्यसपछि SIM सदाका लागि प्रयोग गर्न नमिल्ने हुन्छ। विवरणहरूका लागि सेवा प्रदायकलाई सम्पर्क गर्नुहोस्।</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"समय:"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"बाह्र"</item>
<item msgid="7389464214252023751">"एक"</item>
diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml
index 3bbbb53e2a6b..b3d65bb7e9b4 100644
--- a/packages/SystemUI/res-keyguard/values-nl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">De simkaart is nu uitgeschakeld. Geef de pukcode op om door te gaan. Je hebt nog <xliff:g id="_NUMBER_1">%d</xliff:g> pogingen over voordat de simkaart definitief onbruikbaar wordt. Neem contact op met je provider voor meer informatie.</item>
<item quantity="one">De simkaart is nu uitgeschakeld. Geef de pukcode op om door te gaan. Je hebt nog <xliff:g id="_NUMBER_0">%d</xliff:g> poging over voordat de simkaart definitief onbruikbaar wordt. Neem contact op met je provider voor meer informatie.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Het is"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Twaalf"</item>
<item msgid="7389464214252023751">"Eén"</item>
diff --git a/packages/SystemUI/res-keyguard/values-or/strings.xml b/packages/SystemUI/res-keyguard/values-or/strings.xml
index 0db20aa6881a..94c42c4ccf79 100644
--- a/packages/SystemUI/res-keyguard/values-or/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-or/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM କାର୍ଡକୁ ବର୍ତ୍ତମାନ ଅକ୍ଷମ କରିଦିଆଯାଇଛି। ଜାରି ରଖିବାକୁ PUK କୋଡ୍‍ ଲେଖନ୍ତୁ। ଆଉ <xliff:g id="_NUMBER_1">%d</xliff:g> ଥର ଭୁଲ କୋଡ୍‍ ଲେଖିବା ପରେ SIM କାର୍ଡ ସ୍ଥାୟୀ ଭାବେ ଅନୁପଯୋଗୀ ହୋଇଯିବ। ବିବରଣୀ ପାଇଁ କେରିଅର୍‌ର ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।</item>
<item quantity="one">SIM କାର୍ଡକୁ ବର୍ତ୍ତମାନ ଅକ୍ଷମ କରିଦିଆଯାଇଛି। ଜାରି ରଖିବାକୁ PUK କୋଡ୍‍ ଲେଖନ୍ତୁ। ଆଉ <xliff:g id="_NUMBER_0">%d</xliff:g> ଥର ଭୁଲ କୋଡ୍‍ ଲେଖିବା ପରେ SIM କାର୍ଡ ସ୍ଥାୟୀ ଭାବେ ଅନୁପଯୋଗୀ ହୋଇଯିବ। ବିବରଣୀ ପାଇଁ କେରିଅର୍‌ର ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"ଏବେ"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"ବାର"</item>
<item msgid="7389464214252023751">"ଏକ"</item>
diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml
index 9fd9b197c25e..9b4e28d36ecc 100644
--- a/packages/SystemUI/res-keyguard/values-pa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml
@@ -150,7 +150,7 @@
<item quantity="one">ਸਿਮ ਹੁਣ ਬੰਦ ਹੋ ਗਿਆ ਹੈ। ਜਾਰੀ ਰੱਖਣ ਲਈ PUK ਕੋਡ ਦਾਖਲ ਕਰੋ। ਸਿਮ ਦੇ ਪੱਕੇ ਤੌਰ \'ਤੇ ਬੇਕਾਰ ਹੋ ਜਾਣ ਤੋਂ ਪਹਿਲਾਂ ਤੁਹਾਡੇ ਕੋਲ <xliff:g id="_NUMBER_1">%d</xliff:g> ਕੋਸ਼ਿਸ਼ ਬਾਕੀ ਹੈ। ਵੇਰਵਿਆਂ ਲਈ ਕੈਰੀਅਰ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।</item>
<item quantity="other">ਸਿਮ ਹੁਣ ਬੰਦ ਹੋ ਗਿਆ ਹੈ। ਜਾਰੀ ਰੱਖਣ ਲਈ PUK ਕੋਡ ਦਾਖਲ ਕਰੋ। ਸਿਮ ਦੇ ਪੱਕੇ ਤੌਰ \'ਤੇ ਬੇਕਾਰ ਹੋ ਜਾਣ ਤੋਂ ਪਹਿਲਾਂ ਤੁਹਾਡੇ ਕੋਲ <xliff:g id="_NUMBER_1">%d</xliff:g> ਕੋਸ਼ਿਸ਼ਾਂ ਬਾਕੀ ਹਨ। ਵੇਰਵਿਆਂ ਲਈ ਕੈਰੀਅਰ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"ਸਮਾਂ"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"ਬਾਰਾਂ"</item>
<item msgid="7389464214252023751">"ਇੱਕ"</item>
diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml
index 106fab363270..229443089359 100644
--- a/packages/SystemUI/res-keyguard/values-pl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml
@@ -166,7 +166,7 @@
<item quantity="other">Karta SIM została wyłączona. Wpisz kod PUK, by przejść dalej. Masz jeszcze <xliff:g id="_NUMBER_1">%d</xliff:g> próby, zanim karta SIM zostanie trwale zablokowana. Aby uzyskać szczegółowe informacje, skontaktuj się z operatorem.</item>
<item quantity="one">Karta SIM została wyłączona. Wpisz kod PUK, by przejść dalej. Masz jeszcze <xliff:g id="_NUMBER_0">%d</xliff:g> próbę, zanim karta SIM zostanie trwale zablokowana. Aby uzyskać szczegółowe informacje, skontaktuj się z operatorem.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Jest"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Dwanaście"</item>
<item msgid="7389464214252023751">"Jeden"</item>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
index 3c6a37252ba0..56815ca95d19 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
@@ -150,7 +150,7 @@
<item quantity="one">O chip agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativa restante antes de o chip se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item>
<item quantity="other">O chip agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativas restantes antes de o chip se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"São"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Doze"</item>
<item msgid="7389464214252023751">"Uma"</item>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index 4f601878e958..4e09dc79d237 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">O SIM encontra-se desativado. Introduza o código PUK para continuar. Tem mais <xliff:g id="_NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.</item>
<item quantity="one">O SIM encontra-se desativado. Introduza o código PUK para continuar. Tem mais <xliff:g id="_NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"São"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Doze"</item>
<item msgid="7389464214252023751">"Google One"</item>
diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml
index 3c6a37252ba0..56815ca95d19 100644
--- a/packages/SystemUI/res-keyguard/values-pt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml
@@ -150,7 +150,7 @@
<item quantity="one">O chip agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativa restante antes de o chip se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item>
<item quantity="other">O chip agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativas restantes antes de o chip se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"São"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Doze"</item>
<item msgid="7389464214252023751">"Uma"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml
index 9e4170ec3d6b..23be62ca44f1 100644
--- a/packages/SystemUI/res-keyguard/values-ro/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml
@@ -158,7 +158,7 @@
<item quantity="other">Cardul SIM este dezactivat acum. Introduceți codul PUK pentru a continua. V-au mai rămas <xliff:g id="_NUMBER_1">%d</xliff:g> de încercări până când cardul SIM va deveni inutilizabil definitiv. Contactați operatorul pentru detalii.</item>
<item quantity="one">Cardul SIM este dezactivat acum. Introduceți codul PUK pentru a continua. V-a mai rămas <xliff:g id="_NUMBER_0">%d</xliff:g> încercare până când cardul SIM va deveni inutilizabil definitiv. Contactați operatorul pentru detalii.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Este"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Douăsprezece"</item>
<item msgid="7389464214252023751">"Unu"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml
index dd9bc6a80e4d..f093748d852d 100644
--- a/packages/SystemUI/res-keyguard/values-ru/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml
@@ -166,7 +166,7 @@
<item quantity="many">SIM-карта отключена. Чтобы продолжить, введите PUK-код. Осталось <xliff:g id="_NUMBER_1">%d</xliff:g> попыток. После этого SIM-карта будет заблокирована навсегда. За подробной информацией обратитесь к оператору связи.</item>
<item quantity="other">SIM-карта отключена. Чтобы продолжить, введите PUK-код. Осталось <xliff:g id="_NUMBER_1">%d</xliff:g> попытки. После этого SIM-карта будет заблокирована навсегда. За подробной информацией обратитесь к оператору связи.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Сейчас"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"двенадцать"</item>
<item msgid="7389464214252023751">"один"</item>
diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml
index 59d2a067bd40..17122a575612 100644
--- a/packages/SystemUI/res-keyguard/values-si/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-si/strings.xml
@@ -150,7 +150,7 @@
<item quantity="one">SIM දැන් අබල කර ඇත. දිගටම කරගෙන යාමට PUK කේතය ඇතුළු කරන්න. SIM ස්ථිරවම භාවිත කළ නොහැකි බවට පත් වීමට පෙර ඔබ සතුව උත්සාහයන් <xliff:g id="_NUMBER_1">%d</xliff:g>ක් ඉතිරිව ඇත. විස්තර සඳහා වාහක සම්බන්ධ කර ගන්න.</item>
<item quantity="other">SIM දැන් අබල කර ඇත. දිගටම කරගෙන යාමට PUK කේතය ඇතුළු කරන්න. SIM ස්ථිරවම භාවිත කළ නොහැකි බවට පත් වීමට පෙර ඔබ සතුව උත්සාහයන් <xliff:g id="_NUMBER_1">%d</xliff:g>ක් ඉතිරිව ඇත. විස්තර සඳහා වාහක සම්බන්ධ කර ගන්න.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"ඒ"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"දොළහ"</item>
<item msgid="7389464214252023751">"එක"</item>
diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml
index 0cd5f78ece65..c9919033af61 100644
--- a/packages/SystemUI/res-keyguard/values-sk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml
@@ -166,7 +166,7 @@
<item quantity="other">SIM karta je deaktivovaná. Pokračujte zadaním kódu PUK. Zostáva vám <xliff:g id="_NUMBER_1">%d</xliff:g> pokusov, potom sa SIM karta natrvalo zablokuje. Podrobnosti vám poskytne operátor.</item>
<item quantity="one">SIM karta je deaktivovaná. Pokračujte zadaním kódu PUK. Zostáva vám <xliff:g id="_NUMBER_0">%d</xliff:g> pokus, potom sa SIM karta natrvalo zablokuje. Podrobnosti vám poskytne operátor.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Práve je"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Dvanásť"</item>
<item msgid="7389464214252023751">"Jedna"</item>
diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml
index 52b9d6020ddb..1aba2aae2c71 100644
--- a/packages/SystemUI/res-keyguard/values-sl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml
@@ -166,7 +166,7 @@
<item quantity="few">Kartica SIM je zdaj onemogočena. Če želite nadaljevati, vnesite kodo PUK. Na voljo imate še <xliff:g id="_NUMBER_1">%d</xliff:g> poskuse. Potem bo kartica SIM postala trajno neuporabna. Za podrobnosti se obrnite na operaterja.</item>
<item quantity="other">Kartica SIM je zdaj onemogočena. Če želite nadaljevati, vnesite kodo PUK. Na voljo imate še <xliff:g id="_NUMBER_1">%d</xliff:g> poskusov. Potem bo kartica SIM postala trajno neuporabna. Za podrobnosti se obrnite na operaterja.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Ura je"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Dvanajst"</item>
<item msgid="7389464214252023751">"Ena"</item>
diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml
index 1dfb8fd8b1db..29819e22df88 100644
--- a/packages/SystemUI/res-keyguard/values-sq/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">Karta SIM tani është çaktivizuar. Fut kodin PUK për të vazhduar. Të kanë mbetur edhe <xliff:g id="_NUMBER_1">%d</xliff:g> përpjekje përpara se karta SIM të bëhet përgjithmonë e papërdorshme. Kontakto me operatorin për detaje.</item>
<item quantity="one">Karta SIM tani është çaktivizuar. Fut kodin PUK për të vazhduar. Të ka mbetur edhe <xliff:g id="_NUMBER_0">%d</xliff:g> përpjekje përpara se karta SIM të bëhet përgjithmonë e papërdorshme. Kontakto me operatorin për detaje.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Ora është"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Dymbëdhjetë"</item>
<item msgid="7389464214252023751">"Një"</item>
diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml
index 7bb41e9767fb..d572f9692ac7 100644
--- a/packages/SystemUI/res-keyguard/values-sr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml
@@ -158,7 +158,7 @@
<item quantity="few">SIM је сада онемогућен. Унесите PUK кôд да бисте наставили. Имате још <xliff:g id="_NUMBER_1">%d</xliff:g> покушаја пре него што SIM постане трајно неупотребљив. Детаљне информације потражите од мобилног оператера.</item>
<item quantity="other">SIM је сада онемогућен. Унесите PUK кôд да бисте наставили. Имате још <xliff:g id="_NUMBER_1">%d</xliff:g> покушаја пре него што SIM постане трајно неупотребљив. Детаљне информације потражите од мобилног оператера.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Сада је"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"дванаест"</item>
<item msgid="7389464214252023751">"један"</item>
diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml
index 2475dc1c72b8..6608addcfb19 100644
--- a/packages/SystemUI/res-keyguard/values-sv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM-kortet är inaktiverat. Ange PUK-koden om du vill fortsätta. <xliff:g id="_NUMBER_1">%d</xliff:g> försök återstår innan SIM-kortet blir obrukbart. Kontakta operatören för mer information.</item>
<item quantity="one">SIM-kortet är inaktiverat. Ange PUK-koden om du vill fortsätta. <xliff:g id="_NUMBER_0">%d</xliff:g> försök återstår innan SIM-kortet blir obrukbart. Kontakta operatören för mer information.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Hon är"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Tolv"</item>
<item msgid="7389464214252023751">"En"</item>
diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml
index 0a1acf2f577b..102db535e5d4 100644
--- a/packages/SystemUI/res-keyguard/values-sw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">Sasa SIM imefungwa. Weka msimbo wa PUK ili uendelee. Umesalia na majaribio <xliff:g id="_NUMBER_1">%d</xliff:g> kabla ya SIM kuacha kufanya kazi kabisa. Wasiliana na mtoa huduma kwa maelezo.</item>
<item quantity="one">Sasa SIM imefungwa. Weka msimbo wa PUK ili uendelee. Umesalia na jaribio <xliff:g id="_NUMBER_0">%d</xliff:g> kabla ya SIM kuacha kufanya kazi kabisa. Wasiliana na mtoa huduma kwa maelezo.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Ni saa"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Sita"</item>
<item msgid="7389464214252023751">"Saba"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml
index 57a614a0cfa6..009fb2da2e98 100644
--- a/packages/SystemUI/res-keyguard/values-ta/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">சிம் தற்போது முடக்கப்பட்டுள்ளது. தொடர்வதற்கு, PUK குறியீட்டை உள்ளிடவும். நீங்கள் <xliff:g id="_NUMBER_1">%d</xliff:g> முறை மட்டுமே முயற்சிக்க முடியும். அதன்பிறகு சிம் நிரந்தரமாக முடக்கப்படும். விவரங்களுக்கு, மொபைல் நிறுவனத்தைத் தொடர்புகொள்ளவும்.</item>
<item quantity="one">சிம் தற்போது முடக்கப்பட்டுள்ளது. தொடர்வதற்கு, PUK குறியீட்டை உள்ளிடவும். நீங்கள் <xliff:g id="_NUMBER_0">%d</xliff:g> முறை மட்டுமே முயற்சிக்க முடியும். அதன்பிறகு சிம் நிரந்தரமாக முடக்கப்படும். விவரங்களுக்கு, மொபைல் நிறுவனத்தைத் தொடர்புகொள்ளவும்.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"அதன்"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"பன்னிரண்டு"</item>
<item msgid="7389464214252023751">"ஒன்று"</item>
diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml
index 58880c45cb76..8f4000f84615 100644
--- a/packages/SystemUI/res-keyguard/values-te/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-te/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM ఇప్పుడు నిలిపివేయబడింది. PUK కోడ్‌ను నమోదు చేయండి. SIM శాశ్వతంగా నిరుపయోగం కాకుండా ఉండటానికి మీకు <xliff:g id="_NUMBER_1">%d</xliff:g> ప్రయత్నాలు మిగిలి ఉన్నాయి. వివరాల కోసం కారియర్‌ను సంప్రదించండి.</item>
<item quantity="one">SIM ఇప్పుడు నిలిపివేయబడింది. PUK కోడ్‌ను నమోదు చేయండి. SIM శాశ్వతంగా నిరుపయోగం కాకుండా ఉండటానికి మీకు <xliff:g id="_NUMBER_0">%d</xliff:g> ప్రయత్నం మిగిలి ఉంది వివరాల కోసం కారియర్‌ను సంప్రదించండి.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"ఇప్పుడు"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"పన్నెండు"</item>
<item msgid="7389464214252023751">"ఒకటి"</item>
diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml
index bb52a7f2bdef..bb58e2092721 100644
--- a/packages/SystemUI/res-keyguard/values-th/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-th/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">ซิมถูกปิดใช้งานในขณะนี้ โปรดป้อนรหัส PUK เพื่อทำต่อ คุณพยายามได้อีก <xliff:g id="_NUMBER_1">%d</xliff:g> ครั้งก่อนที่ซิมจะไม่สามารถใช้งานได้อย่างถาวร โปรดติดต่อสอบถามรายละเอียดจากผู้ให้บริการ</item>
<item quantity="one">ซิมถูกปิดใช้งานในขณะนี้ โปรดป้อนรหัส PUK เพื่อทำต่อ คุณพยายามได้อีก <xliff:g id="_NUMBER_0">%d</xliff:g> ครั้งก่อนที่ซิมจะไม่สามารถใช้งานได้อย่างถาวร โปรดติดต่อสอบถามรายละเอียดจากผู้ให้บริการ</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"เวลา"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"สิบสอง"</item>
<item msgid="7389464214252023751">"หนึ่ง"</item>
diff --git a/packages/SystemUI/res-keyguard/values-tl/strings.xml b/packages/SystemUI/res-keyguard/values-tl/strings.xml
index 1f480f40379f..ec7b924969a3 100644
--- a/packages/SystemUI/res-keyguard/values-tl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tl/strings.xml
@@ -150,7 +150,7 @@
<item quantity="one">Naka-disable na ang SIM. Ilagay ang PUK code upang magpatuloy. Mayroon kang <xliff:g id="_NUMBER_1">%d</xliff:g> natitirang pagsubok bago tuluyang hindi magamit ang SIM. Makipag-ugnayan sa carrier para sa mga detalye.</item>
<item quantity="other">Naka-disable na ang SIM. Ilagay ang PUK code upang magpatuloy. Mayroon kang <xliff:g id="_NUMBER_1">%d</xliff:g> na natitirang pagsubok bago tuluyang hindi magamit ang SIM. Makipag-ugnayan sa carrier para sa mga detalye.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Oras ay"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Twelve"</item>
<item msgid="7389464214252023751">"One"</item>
diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml
index 8ff1d88ee83a..92b3fb37d6f7 100644
--- a/packages/SystemUI/res-keyguard/values-tr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM artık devre dışı. Devam etmek için PUK kodunu girin. SIM kalıcı olarak kullanım dışı kalmadan önce <xliff:g id="_NUMBER_1">%d</xliff:g> deneme hakkınız kaldı. Ayrıntılı bilgi için operatörünüzle iletişim kurun.</item>
<item quantity="one">SIM artık devre dışı. Devam etmek için PUK kodunu girin. SIM kalıcı olarak kullanım dışı kalmadan önce <xliff:g id="_NUMBER_0">%d</xliff:g> deneme hakkınız kaldı. Ayrıntılı bilgi için operatörünüzle iletişim kurun.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Saat"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"On İki"</item>
<item msgid="7389464214252023751">"Bir"</item>
diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml
index 3f0982fe5d47..2772d0738334 100644
--- a/packages/SystemUI/res-keyguard/values-uk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml
@@ -166,7 +166,7 @@
<item quantity="many">SIM-карту заблоковано. Щоб продовжити, введіть PUK-код. Залишилося <xliff:g id="_NUMBER_1">%d</xliff:g> спроб. Після цього SIM-карту буде назавжди заблоковано. Щоб дізнатися більше, зверніться до свого оператора.</item>
<item quantity="other">SIM-карту заблоковано. Щоб продовжити, введіть PUK-код. Залишилося <xliff:g id="_NUMBER_1">%d</xliff:g> спроби. Після цього SIM-карту буде назавжди заблоковано. Щоб дізнатися більше, зверніться до свого оператора.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Зараз"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"дванадцята"</item>
<item msgid="7389464214252023751">"перша"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml
index 3c520f955b93..e9e67097cfa8 100644
--- a/packages/SystemUI/res-keyguard/values-ur/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">‏SIM اب غیر فعال ہے۔ جاری رکھنے کیلئے PUK کوڈ درج کریں۔ SIM کے مستقل طور پر ناقابل استعمال ہونے سے پہلے آپ کے پاس <xliff:g id="_NUMBER_1">%d</xliff:g> کوششیں بچی ہیں۔ تفصیلات کیلئے کیریئر سے رابطہ کریں۔</item>
<item quantity="one">‏SIM اب غیر فعال ہے۔ جاری رکھنے کیلئے PUK کوڈ درج کریں۔ SIM کے مستقل طور پر ناقابل استعمال ہونے سے پہلے آپ کے پاس <xliff:g id="_NUMBER_0">%d</xliff:g> کوشش بچی ہے۔ تفصیلات کیلئے کیریئر سے رابطہ کریں۔</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"وقت/ابھی"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"بارہ"</item>
<item msgid="7389464214252023751">"ایک"</item>
diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml
index 640a98760f2f..676f7bb97de6 100644
--- a/packages/SystemUI/res-keyguard/values-uz/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml
@@ -152,7 +152,7 @@
<item quantity="other">SIM karta faolsizlantirildi. Davom etish uchun PUK kodni kiriting. Yana <xliff:g id="_NUMBER_1">%d</xliff:g> marta xato qilsangiz, SIM kartangiz butunlay qulflanadi. Batafsil axborot olish uchun tarmoq operatoriga murojaat qiling.</item>
<item quantity="one">SIM karta faolsizlantirildi. Davom etish uchun PUK kodni kiriting. Yana <xliff:g id="_NUMBER_0">%d</xliff:g> marta xato qilsangiz, SIM kartangiz butunlay qulflanadi. Batafsil axborot olish uchun tarmoq operatoriga murojaat qiling.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Hozir"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Oʻn ikki"</item>
<item msgid="7389464214252023751">"Bir"</item>
diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml
index 2a62fb878231..f2cfb2a2a23e 100644
--- a/packages/SystemUI/res-keyguard/values-vi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM hiện đã bị tắt. Hãy nhập mã PUK để tiếp tục. Bạn còn <xliff:g id="_NUMBER_1">%d</xliff:g> lần thử trước khi SIM vĩnh viễn không sử dụng được. Hãy liên hệ với nhà cung cấp dịch vụ để biết chi tiết.</item>
<item quantity="one">SIM hiện đã bị tắt. Hãy nhập mã PUK để tiếp tục. Bạn còn <xliff:g id="_NUMBER_0">%d</xliff:g> lần thử trước khi SIM vĩnh viễn không thể sử dụng được. Hãy liên hệ với nhà cung cấp dịch vụ để biết chi tiết.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Hiện là"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Mười hai"</item>
<item msgid="7389464214252023751">"Một"</item>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
index 80fac9030fe0..efa5fc35ff1c 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM 卡现已停用,请输入 PUK 码继续使用。您还可以尝试 <xliff:g id="_NUMBER_1">%d</xliff:g> 次。如果仍不正确,该 SIM 卡将永远无法使用。有关详情,请联系您的运营商。</item>
<item quantity="one">SIM 卡现已停用,请输入 PUK 码继续使用。您还可以尝试 <xliff:g id="_NUMBER_0">%d</xliff:g> 次。如果仍不正确,该 SIM 卡将永远无法使用。有关详情,请联系您的运营商。</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"时间是"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"十二"</item>
<item msgid="7389464214252023751">"一"</item>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
index 926d601ebb5a..eeff66acd9a8 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM 卡已停用。請輸入 PUK 碼以繼續進行。您還可以再試 <xliff:g id="_NUMBER_1">%d</xliff:g> 次。如果仍然輸入錯誤,SIM 卡將永久無法使用。詳情請與流動網絡供應商聯絡。</item>
<item quantity="one">SIM 卡已停用。請輸入 PUK 碼以繼續進行。您還可以再試 <xliff:g id="_NUMBER_0">%d</xliff:g> 次。如果仍然輸入錯誤,SIM 卡將永久無法使用。詳情請與流動網絡供應商聯絡。</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"現在是"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"十二"</item>
<item msgid="7389464214252023751">"一"</item>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
index 728f1a97996f..961ef39f3809 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
@@ -150,7 +150,7 @@
<item quantity="other">SIM 卡現在已遭停用。請輸入 PUK 碼以繼續進行。你還可以再試 <xliff:g id="_NUMBER_1">%d</xliff:g> 次,如果仍然失敗,SIM 卡將永久無法使用。詳情請與電信業者聯絡。</item>
<item quantity="one">SIM 卡現在已遭停用。請輸入 PUK 碼以繼續進行。你還可以再試 <xliff:g id="_NUMBER_0">%d</xliff:g> 次,如果仍然失敗,SIM 卡將永久無法使用。詳情請與電信業者聯絡。</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"時間是"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"十二"</item>
<item msgid="7389464214252023751">"一"</item>
diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml
index 7e0a03c02c94..2e948b485276 100644
--- a/packages/SystemUI/res-keyguard/values-zu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zu/strings.xml
@@ -150,7 +150,7 @@
<item quantity="one">I-SIM manje ikhutshaziwe. Faka ikhodi ye-PUK ukuze uqhubeke. Unemizamo engu-<xliff:g id="_NUMBER_1">%d</xliff:g> esele ngaphambi kokuthi i-SIM ingasebenziseki unaphakade. Xhumana nenkampani yenethiwekhi ngemininingwane.</item>
<item quantity="other">I-SIM manje ikhutshaziwe. Faka ikhodi ye-PUK ukuze uqhubeke. Unemizamo engu-<xliff:g id="_NUMBER_1">%d</xliff:g> esele ngaphambi kokuthi i-SIM ingasebenziseki unaphakade. Xhumana nenkampani yenethiwekhi ngemininingwane.</item>
</plurals>
- <string name="type_clock_header" msgid="4786545441902447636">"Kuyi-"</string>
+ <!-- no translation found for type_clock_header (6782840450655632763) -->
<string-array name="type_clock_hours">
<item msgid="3543074812389379830">"Ishumi nambili"</item>
<item msgid="7389464214252023751">"Kunye"</item>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index e2ba23ec898c..b6a41c19ec32 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -42,18 +42,18 @@
<dimen name="eca_overlap">-10dip</dimen>
<!-- Slice header -->
- <dimen name="widget_title_font_size">24dp</dimen>
- <dimen name="widget_title_bottom_margin">14dp</dimen>
- <dimen name="bottom_text_spacing_digital">0dp</dimen>
+ <dimen name="widget_title_font_size">22dp</dimen>
+ <dimen name="header_subtitle_padding">4dp</dimen>
+ <dimen name="header_icon_size">20dp</dimen>
<!-- Slice subtitle -->
<dimen name="widget_label_font_size">16dp</dimen>
<!-- Clock without header -->
<dimen name="widget_big_font_size">64dp</dimen>
+ <dimen name="bottom_text_spacing_digital">0dp</dimen>
<!-- Clock with header -->
- <dimen name="widget_small_clock_padding">-25dp</dimen>
- <dimen name="widget_small_font_size">24dp</dimen>
- <dimen name="widget_small_font_stroke">0.6dp</dimen>
+ <dimen name="widget_small_font_size">22dp</dimen>
<dimen name="widget_vertical_padding">32dp</dimen>
+ <dimen name="widget_vertical_padding_clock">30dp</dimen>
<!-- Subtitle paddings -->
<dimen name="widget_horizontal_padding">8dp</dimen>
<dimen name="widget_icon_size">16dp</dimen>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 94481e7fe456..5714556ae8a3 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -64,6 +64,9 @@
charged, say that it is charged. -->
<string name="keyguard_charged">Fully charged</string>
+ <!-- When the lock screen is showing and the phone plugged in, and the battery is not fully charged, say that it's wirelessly charging. [CHAR LIMIT=50] -->
+ <string name="keyguard_plugged_in_wireless"><xliff:g id="percentage" example="20%">%s</xliff:g> • Wirelessly Charging</string>
+
<!-- When the lock screen is showing and the phone plugged in, and the battery
is not fully charged, say that it's charging. -->
<string name="keyguard_plugged_in"><xliff:g id="percentage">%s</xliff:g> • Charging</string>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml
index b673e4f3b081..dd124b713a72 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml
@@ -14,12 +14,19 @@ Copyright (C) 2017 The Android Open Source Project
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal" >
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?android:attr/colorControlNormal">
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L11,14.41V22h1l5.71-5.71L13.41,12L17.71,7.71z M13,5.83 l1.88,1.88L13,9.59V5.83z M14.88,16.29L13,18.17v-3.76L14.88,16.29z" />
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M 5 10.5 C 5.82842712475 10.5 6.5 11.1715728753 6.5 12 C 6.5 12.8284271247 5.82842712475 13.5 5 13.5 C 4.17157287525 13.5 3.5 12.8284271247 3.5 12 C 3.5 11.1715728753 4.17157287525 10.5 5 10.5 Z" />
<path
- android:pathData="M13.51,12l3.75,-3.74c0.41,-0.41 0.41,-1.07 0,-1.48l-4.47,-4.47 -0.03,-0.03a1.046,1.046 0,0 0,-1.76 0.76v6.44L6.95,5.43c-0.41,-0.41 -1.06,-0.41 -1.47,0s-0.41,1.06 0,1.47l5.09,5.1 -5.09,5.09c-0.41,0.41 -0.41,1.06 0,1.47s1.06,0.41 1.47,0L11,14.51v6.45a1.04,1.04 0,0 0,1.75 0.76l0.05,-0.05 4.46,-4.46c0.41,-0.41 0.41,-1.07 0,-1.48L13.51,12zM12.99,9.67v-4.3l2.15,2.15 -2.15,2.15zM12.99,18.62v-4.3l2.15,2.15 -2.15,2.15zM6.06,13.06c-0.59,0.59 -1.54,0.59 -2.12,0a1.49,1.49 0,0 1,0 -2.12,1.49 1.49,0 0,1 2.12,0c0.59,0.59 0.59,1.53 0,2.12zM20.06,10.94c0.59,0.59 0.59,1.54 0,2.12 -0.59,0.59 -1.54,0.59 -2.12,0a1.49,1.49 0,0 1,0 -2.12,1.49 1.49,0 0,1 2.12,0z"
- android:fillColor="#FFFFFFFF" />
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M 19 10.5 C 19.8284271247 10.5 20.5 11.1715728753 20.5 12 C 20.5 12.8284271247 19.8284271247 13.5 19 13.5 C 18.1715728753 13.5 17.5 12.8284271247 17.5 12 C 17.5 11.1715728753 18.1715728753 10.5 19 10.5 Z" />
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
index 8cc6caa8abc8..220c63ccca6d 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
@@ -14,12 +14,13 @@ Copyright (C) 2017 The Android Open Source Project
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="64dp"
- android:height="64dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal">
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?android:attr/colorControlNormal">
+
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M13.5,12l3.8,-3.7c0.4,-0.4 0.4,-1.1 0,-1.5l-4.5,-4.5c-0.4,-0.4 -1.1,-0.4 -1.5,0.1C11.1,2.5 11,2.8 11,3v6.4L6.9,5.4C6.5,5 5.9,5 5.5,5.4s-0.4,1.1 0,1.5l5.1,5.1l-5.1,5.1c-0.4,0.4 -0.4,1.1 0,1.5s1.1,0.4 1.5,0l4.1,-4V21c0,0.6 0.5,1 1,1c0.3,0 0.5,-0.1 0.7,-0.3l0.1,0l4.5,-4.5c0.4,-0.4 0.4,-1.1 0,-1.5L13.5,12zM13,9.7V5.4l2.1,2.2L13,9.7zM13,18.6v-4.3l2.1,2.2L13,18.6z"/>
+ android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L11,14.41V22h1l5.71-5.71L13.41,12L17.71,7.71z M13,5.83 l1.88,1.88L13,9.59V5.83z M14.88,16.29L13,18.17v-3.76L14.88,16.29z" />
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_signal_airplane.xml b/packages/SystemUI/res/drawable/ic_signal_airplane.xml
index 0a4d7526a55d..f708ed9cb8a6 100644
--- a/packages/SystemUI/res/drawable/ic_signal_airplane.xml
+++ b/packages/SystemUI/res/drawable/ic_signal_airplane.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2017 The Android Open Source Project
+ Copyright (C) 2019 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,16 +15,12 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="20.5"
- android:viewportHeight="20.5">
- <group
- android:translateX="1.75"
- android:translateY="1.4">
- <path
- android:pathData="M16.01,9.87l-6.24,-3.9v-4.7C9.77,0.57 9.21,0 8.5,0S7.23,0.57 7.23,1.28v4.7L0.99,9.88c-0.37,0.23 -0.6,0.64 -0.6,1.08v0.41c0,0.29 0.29,0.5 0.55,0.41l6.27,-1.97v4.7l-1.37,1.02c-0.21,0.16 -0.34,0.41 -0.34,0.68v0.57c0,0.15 0.12,0.23 0.27,0.2 1.67,-0.47 1.12,-0.31 2.73,-0.78 1.03,0.3 1.7,0.49 2.72,0.78 0.15,0.03 0.27,-0.06 0.27,-0.2v-0.57c0,-0.27 -0.13,-0.52 -0.34,-0.68l-1.37,-1.02v-4.7l6.27,1.97c0.28,0.09 0.55,-0.12 0.55,-0.41v-0.41c0.01,-0.45 -0.23,-0.87 -0.59,-1.09z"
- android:fillColor="#FFF"/>
- </group>
-</vector>
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+<path
+ android:fillColor="#FFFFFF"
+ android:pathData="M21,16v-2l-8-5V3.5C13,2.67,12.33,2,11.5,2S10,2.67,10,3.5V9l-8,5v2l8-2.5V19l-2,1.5V22l3.5-1l3.5,1v-1.5L13,19v-5.5L21,16z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/privacy_chip_bg.xml b/packages/SystemUI/res/drawable/privacy_chip_bg.xml
index 36d06591460b..f1158ef11ccc 100644
--- a/packages/SystemUI/res/drawable/privacy_chip_bg.xml
+++ b/packages/SystemUI/res/drawable/privacy_chip_bg.xml
@@ -17,6 +17,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#4a4a4a" />
- <padding android:padding="@dimen/ongoing_appops_chip_bg_padding" />
+ <padding android:paddingTop="@dimen/ongoing_appops_chip_bg_padding"
+ android:paddingBottom="@dimen/ongoing_appops_chip_bg_padding"/>
<corners android:radius="@dimen/ongoing_appops_chip_bg_corner_radius" />
</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/rounded_bg.xml b/packages/SystemUI/res/drawable/rounded_bg.xml
index c23a87fbfb79..3de67de95f31 100644
--- a/packages/SystemUI/res/drawable/rounded_bg.xml
+++ b/packages/SystemUI/res/drawable/rounded_bg.xml
@@ -3,8 +3,8 @@
android:shape="rectangle">
<solid android:color="?android:attr/colorPrimary" />
<corners
- android:bottomLeftRadius="@dimen/corner_size"
- android:topLeftRadius="@dimen/corner_size"
+ android:bottomLeftRadius="?android:attr/dialogCornerRadius"
+ android:topLeftRadius="?android:attr/dialogCornerRadius"
android:bottomRightRadius="0dp"
android:topRightRadius="0dp"
/>
diff --git a/packages/SystemUI/res/drawable/rounded_bg_bottom.xml b/packages/SystemUI/res/drawable/rounded_bg_bottom.xml
index b3bea635f953..7db59e9bad7c 100644
--- a/packages/SystemUI/res/drawable/rounded_bg_bottom.xml
+++ b/packages/SystemUI/res/drawable/rounded_bg_bottom.xml
@@ -3,7 +3,7 @@
android:shape="rectangle">
<solid android:color="?android:attr/colorPrimaryDark" />
<corners
- android:bottomLeftRadius="@dimen/corner_size"
+ android:bottomLeftRadius="?android:attr/dialogCornerRadius"
android:topLeftRadius="0dp"
android:bottomRightRadius="0dp"
android:topRightRadius="0dp"
diff --git a/packages/SystemUI/res/drawable/rounded_bg_bottom_background.xml b/packages/SystemUI/res/drawable/rounded_bg_bottom_background.xml
index 622226f25de3..382ca20268b7 100644
--- a/packages/SystemUI/res/drawable/rounded_bg_bottom_background.xml
+++ b/packages/SystemUI/res/drawable/rounded_bg_bottom_background.xml
@@ -3,9 +3,9 @@
android:shape="rectangle">
<solid android:color="?android:attr/panelColorBackground" />
<corners
- android:bottomLeftRadius="@dimen/corner_size"
+ android:bottomLeftRadius="?android:attr/dialogCornerRadius"
android:topLeftRadius="0dp"
- android:bottomRightRadius="@dimen/corner_size"
+ android:bottomRightRadius="?android:attr/dialogCornerRadius"
android:topRightRadius="0dp"
/>
</shape>
diff --git a/packages/SystemUI/res/drawable/rounded_bg_full.xml b/packages/SystemUI/res/drawable/rounded_bg_full.xml
index 03f18bb5d680..e0d3f63e8f40 100644
--- a/packages/SystemUI/res/drawable/rounded_bg_full.xml
+++ b/packages/SystemUI/res/drawable/rounded_bg_full.xml
@@ -3,9 +3,9 @@
android:shape="rectangle">
<solid android:color="?android:attr/colorBackgroundFloating" />
<corners
- android:bottomLeftRadius="@dimen/corner_size"
- android:topLeftRadius="@dimen/corner_size"
- android:bottomRightRadius="@dimen/corner_size"
- android:topRightRadius="@dimen/corner_size"
+ android:bottomLeftRadius="?android:attr/dialogCornerRadius"
+ android:topLeftRadius="?android:attr/dialogCornerRadius"
+ android:bottomRightRadius="?android:attr/dialogCornerRadius"
+ android:topRightRadius="?android:attr/dialogCornerRadius"
/>
</shape>
diff --git a/packages/SystemUI/res/drawable/rounded_full_bg_bottom.xml b/packages/SystemUI/res/drawable/rounded_full_bg_bottom.xml
index a4b3c99f7ec6..a62657d14afc 100644
--- a/packages/SystemUI/res/drawable/rounded_full_bg_bottom.xml
+++ b/packages/SystemUI/res/drawable/rounded_full_bg_bottom.xml
@@ -17,9 +17,9 @@
android:shape="rectangle">
<solid android:color="?android:attr/colorPrimaryDark" />
<corners
- android:bottomLeftRadius="@dimen/corner_size"
+ android:bottomLeftRadius="?android:attr/dialogCornerRadius"
android:topLeftRadius="0dp"
- android:bottomRightRadius="@dimen/corner_size"
+ android:bottomRightRadius="?android:attr/dialogCornerRadius"
android:topRightRadius="0dp"
/>
</shape>
diff --git a/packages/SystemUI/res/layout-land/global_actions_grid.xml b/packages/SystemUI/res/layout-land/global_actions_grid.xml
new file mode 100644
index 000000000000..911b661d48eb
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/global_actions_grid.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.android.systemui.globalactions.GlobalActionsGridLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@id/global_actions_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:clipToPadding="false"
+ android:theme="@style/qs_theme"
+ android:gravity="top|right"
+ android:clipChildren="false"
+>
+
+ <LinearLayout
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:gravity="top|right"
+ android:padding="0dp"
+ android:orientation="vertical"
+ android:layoutDirection="ltr"
+ android:layout_marginRight="@dimen/global_actions_grid_container_bottom_margin"
+ >
+ <!-- Grid of action items -->
+ <com.android.systemui.globalactions.ListGridLayout
+ android:id="@android:id/list"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layoutDirection="ltr"
+ android:layout_marginTop="@dimen/global_actions_grid_side_margin"
+ android:translationZ="@dimen/global_actions_translate"
+ android:paddingLeft="@dimen/global_actions_grid_top_padding"
+ android:paddingRight="@dimen/global_actions_grid_bottom_padding"
+ android:paddingTop="@dimen/global_actions_grid_left_padding"
+ android:paddingBottom="@dimen/global_actions_grid_right_padding"
+ android:background="?android:attr/colorBackgroundFloating"
+ >
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:layoutDirection="ltr"
+ android:orientation="horizontal"
+ />
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:layoutDirection="ltr"
+ android:orientation="horizontal"
+ />
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:layoutDirection="ltr"
+ android:orientation="horizontal"
+ />
+ </com.android.systemui.globalactions.ListGridLayout>
+
+ <!-- For separated items-->
+ <LinearLayout
+ android:id="@+id/separated_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/global_actions_grid_side_margin"
+ android:layout_marginBottom="@dimen/global_actions_grid_side_margin"
+ android:paddingTop="@dimen/global_actions_grid_left_padding"
+ android:paddingLeft="@dimen/global_actions_grid_top_padding"
+ android:paddingBottom="@dimen/global_actions_grid_right_padding"
+ android:paddingRight="@dimen/global_actions_grid_bottom_padding"
+ android:orientation="horizontal"
+ android:layoutDirection="ltr"
+ android:background="?android:attr/colorBackgroundFloating"
+ android:translationZ="@dimen/global_actions_translate"
+ />
+
+ </LinearLayout>
+
+</com.android.systemui.globalactions.GlobalActionsGridLayout>
diff --git a/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml b/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml
new file mode 100644
index 000000000000..669be1b40567
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.android.systemui.globalactions.GlobalActionsGridLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@id/global_actions_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:clipToPadding="false"
+ android:theme="@style/qs_theme"
+ android:gravity="top|left"
+ android:clipChildren="false"
+>
+
+ <LinearLayout
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:gravity="bottom|left"
+ android:padding="0dp"
+ android:orientation="vertical"
+ android:layout_marginLeft="@dimen/global_actions_grid_container_bottom_margin"
+ >
+ <!-- For separated items-->
+ <LinearLayout
+ android:id="@+id/separated_button"
+ android:layout_gravity="top|left"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/global_actions_grid_side_margin"
+ android:layout_marginBottom="@dimen/global_actions_grid_side_margin"
+ android:paddingTop="@dimen/global_actions_grid_left_padding"
+ android:paddingLeft="@dimen/global_actions_grid_top_padding"
+ android:paddingBottom="@dimen/global_actions_grid_right_padding"
+ android:paddingRight="@dimen/global_actions_grid_bottom_padding"
+ android:orientation="horizontal"
+ android:layoutDirection="rtl"
+ android:background="?android:attr/colorBackgroundFloating"
+ android:translationZ="@dimen/global_actions_translate"
+ />
+
+ <!-- Grid of action items -->
+ <com.android.systemui.globalactions.ListGridLayout
+ android:id="@android:id/list"
+ android:layout_gravity="bottom|left"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_marginTop="@dimen/global_actions_grid_side_margin"
+ android:translationZ="@dimen/global_actions_translate"
+ android:paddingLeft="@dimen/global_actions_grid_top_padding"
+ android:paddingRight="@dimen/global_actions_grid_bottom_padding"
+ android:paddingTop="@dimen/global_actions_grid_left_padding"
+ android:paddingBottom="@dimen/global_actions_grid_right_padding"
+ android:background="?android:attr/colorBackgroundFloating"
+ >
+ <LinearLayout
+ android:layout_gravity="bottom"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:layoutDirection="rtl"
+ android:orientation="horizontal"
+ />
+ <LinearLayout
+ android:layout_gravity="bottom"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:layoutDirection="rtl"
+ android:orientation="horizontal"
+ />
+ <LinearLayout
+ android:layout_gravity="bottom"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:layoutDirection="rtl"
+ android:orientation="horizontal"
+ />
+ </com.android.systemui.globalactions.ListGridLayout>
+ </LinearLayout>
+
+</com.android.systemui.globalactions.GlobalActionsGridLayout>
diff --git a/packages/SystemUI/res/layout/global_actions_grid.xml b/packages/SystemUI/res/layout/global_actions_grid.xml
index e6f2376ae76b..1b56fa089281 100644
--- a/packages/SystemUI/res/layout/global_actions_grid.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid.xml
@@ -12,10 +12,11 @@
>
<LinearLayout
- android:layout_height="290dp"
- android:layout_width="412dp"
- android:gravity="bottom"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:gravity="bottom | right"
android:padding="0dp"
+ android:layoutDirection="ltr"
android:layout_marginBottom="@dimen/global_actions_grid_container_bottom_margin"
>
<!-- For separated items-->
@@ -34,15 +35,11 @@
android:translationZ="@dimen/global_actions_translate"
/>
- <Space android:layout_width="match_parent" android:layout_height="2dp"
- android:layout_weight="1" />
-
<!-- Grid of action items -->
<com.android.systemui.globalactions.ListGridLayout
android:id="@android:id/list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:gravity="right"
android:orientation="horizontal"
android:layoutDirection="rtl"
android:layout_marginRight="@dimen/global_actions_grid_side_margin"
@@ -56,25 +53,19 @@
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="bottom|right"
android:visibility="gone"
- android:gravity="bottom"
android:orientation="vertical"
/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="bottom|right"
android:visibility="gone"
- android:gravity="bottom"
android:orientation="vertical"
/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="bottom|right"
android:visibility="gone"
- android:gravity="bottom"
android:orientation="vertical"
/>
</com.android.systemui.globalactions.ListGridLayout>
diff --git a/packages/SystemUI/res/layout/global_actions_grid_item.xml b/packages/SystemUI/res/layout/global_actions_grid_item.xml
index 0c11cd977256..a8938390690f 100644
--- a/packages/SystemUI/res/layout/global_actions_grid_item.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid_item.xml
@@ -47,6 +47,7 @@
android:gravity="center"
android:textSize="12sp"
android:textAppearance="?android:attr/textAppearanceSmall"
+ android:singleLine="true"
/>
<TextView
@@ -57,5 +58,6 @@
android:gravity="center"
android:textColor="?android:attr/textColorTertiary"
android:textAppearance="?android:attr/textAppearanceSmall"
+ android:singleLine="true"
/>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index d502baa956b0..91353d7fb8ba 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -71,18 +71,38 @@
android:maxLines="1"
android:layout_centerVertical="true"
android:layout_toEndOf="@id/pkg_divider" />
- <!-- 24 dp icon with 16 dp padding all around to mirror notification content margins -->
- <ImageButton
- android:id="@+id/info"
- android:layout_width="56dp"
- android:layout_height="56dp"
- android:layout_alignParentEnd="true"
+ <LinearLayout
+ android:id="@+id/info_and_settings"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_centerVertical="true"
- android:background="@drawable/ripple_drawable"
- android:contentDescription="@string/notification_more_settings"
- android:padding="16dp"
- android:src="@drawable/ic_info"
- android:tint="?android:attr/colorAccent" />
+ android:layout_alignParentEnd="true"
+ android:paddingHorizontal="16dp"
+ android:orientation="horizontal">
+ <!-- Optional link to app. Only appears if the channel is not disabled and the app
+asked for it -->
+ <ImageButton
+ android:id="@+id/app_settings"
+ android:layout_width="40dp"
+ android:layout_height="56dp"
+ android:layout_centerVertical="true"
+ android:paddingRight="16dp"
+ android:visibility="gone"
+ android:background="@drawable/ripple_drawable"
+ android:contentDescription="@string/notification_app_settings"
+ android:src="@drawable/ic_settings"
+ android:tint="?android:attr/colorAccent" />
+ <!-- 24 dp icon with 16 dp padding all around to mirror notification content margins -->
+ <ImageButton
+ android:id="@+id/info"
+ android:layout_width="24dp"
+ android:layout_height="56dp"
+ android:layout_centerVertical="true"
+ android:background="@drawable/ripple_drawable"
+ android:contentDescription="@string/notification_more_settings"
+ android:src="@drawable/ic_info"
+ android:tint="?android:attr/colorAccent" />
+ </LinearLayout>
</RelativeLayout>
<LinearLayout
@@ -143,50 +163,61 @@
</LinearLayout>
<!-- Settings and Done buttons -->
- <LinearLayout
+ <RelativeLayout
android:id="@+id/block_or_minimize"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/notification_guts_button_spacing"
android:layout_marginStart="@dimen/notification_guts_button_side_margin"
android:layout_marginEnd="@dimen/notification_guts_button_side_margin"
- android:gravity="end"
- android:orientation="horizontal">
-
- <!-- Optional link to app. Only appears if the channel is not disabled and the app
- asked for it -->
+ android:clipChildren="false"
+ android:clipToPadding="false">
<TextView
- android:id="@+id/app_settings"
- android:text="@string/notification_app_settings"
+ android:id="@+id/done"
+ android:text="@string/inline_done_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:visibility="gone"
- android:ellipsize="end"
- android:maxLines="1"
+ android:layout_centerVertical="true"
style="@style/TextAppearance.NotificationInfo.Button"/>
- <TextView
- android:id="@+id/block"
- android:text="@string/inline_stop_button"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
- style="@style/TextAppearance.NotificationInfo.Button"/>
- <TextView
- android:id="@+id/minimize"
- android:text="@string/inline_minimize_button"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
- style="@style/TextAppearance.NotificationInfo.Button" />
- <TextView
- android:id="@+id/keep"
- android:minWidth="48dp"
- android:text="@string/inline_keep_button"
+
+ <LinearLayout
+ android:id="@+id/block_buttons"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
- style="@style/TextAppearance.NotificationInfo.Button"/>
- </LinearLayout>
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_alignParentEnd="true"
+ android:orientation="horizontal">
+ <TextView
+ android:id="@+id/deliver_silently"
+ android:text="@string/inline_deliver_silently_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
+ android:paddingRight="24dp"
+ style="@style/TextAppearance.NotificationInfo.Button"/>
+ <TextView
+ android:id="@+id/block"
+ android:text="@string/inline_block_button"
+ android:minWidth="48dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
+ style="@style/TextAppearance.NotificationInfo.Button"/>
+ <TextView
+ android:id="@+id/minimize"
+ android:text="@string/inline_minimize_button"
+ android:minWidth="48dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
+ style="@style/TextAppearance.NotificationInfo.Button"/>
+ </LinearLayout>
+
+
+ </RelativeLayout>
<LinearLayout
android:id="@+id/interruptiveness_settings"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
index cbdd51b24388..58fe81109731 100644
--- a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
@@ -29,14 +29,25 @@
android:orientation="horizontal"
android:paddingStart="@dimen/ongoing_appops_chip_side_padding"
android:paddingEnd="@dimen/ongoing_appops_chip_side_padding"
- android:background="@drawable/privacy_chip_bg"
android:focusable="true">
+ <TextView
+ android:id="@+id/in_use_text"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical|start"
+ android:layout_marginEnd="@dimen/ongoing_appops_chip_icon_margin_collapsed"
+ android:gravity="center_vertical"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+ android:textColor="@color/status_bar_clock_color"
+ android:text="@string/ongoing_privacy_chip_in_use"
+ />
+
<LinearLayout
android:id="@+id/icons_container"
android:layout_height="match_parent"
android:layout_width="wrap_content"
- android:layout_gravity="center_vertical|start"
+ android:layout_gravity="center_vertical"
android:gravity="center_vertical"
/>
@@ -51,7 +62,7 @@
android:gravity="center_vertical"
android:textAppearance="@style/TextAppearance.StatusBar.Clock"
android:textColor="@color/status_bar_clock_color"
- android:layout_marginStart="@dimen/ongoing_appops_chip_icon_margin"
- android:layout_marginEnd="@dimen/ongoing_appops_chip_icon_margin"
+ android:layout_marginStart="@dimen/ongoing_appops_chip_icon_margin_collapsed"
+ android:layout_marginEnd="@dimen/ongoing_appops_chip_icon_margin_collapsed"
/>
</com.android.systemui.privacy.OngoingPrivacyChip> \ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 053371a0e527..9b765f824859 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> program gebruik jou <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Het dit"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privaatheidsinstellings"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Program wat jou <xliff:g id="TYPES_LIST">%s</xliff:g> gebruik"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Programme wat jou <xliff:g id="TYPES_LIST">%s</xliff:g> gebruik"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors is af"</string>
<string name="device_services" msgid="1191212554435440592">"Toesteldienste"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Titelloos"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Maak <xliff:g id="APP_NAME">%1$s</xliff:g> oop"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Maak kennisgewinginstellings oop vir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 8acd1b832ed3..d12ba4ca08a4 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -879,8 +879,7 @@
<item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> መተግበሪያዎች የእርስዎን <xliff:g id="TYPE_5">%2$s</xliff:g> እየተጠቀሙ ነው።</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"ገባኝ"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"የግላዊነት ቅንብሮች"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"የእርስዎን <xliff:g id="TYPES_LIST">%s</xliff:g> የሚጠቀሙ መተግበሪያዎች"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"የእርስዎን <xliff:g id="TYPES_LIST">%s</xliff:g> የሚጠቀሙ መተግበሪያዎች"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"፣ "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"ዳሳሾች ጠፍተዋል"</string>
<string name="device_services" msgid="1191212554435440592">"የመሣሪያ አገልግሎቶች"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"ርዕስ የለም"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> ክፈት"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"የማስታወቂያ ቅንብሮች ለ <xliff:g id="APP_NAME">%1$s</xliff:g> ክፈት"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 0312adf36f23..7c08783e365d 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -907,8 +907,7 @@
<item quantity="one">هناك تطبيق واحد (<xliff:g id="NUM_APPS_0">%1$d</xliff:g>) يستخدِم <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"حسنًا"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"إعدادات الخصوصية"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"التطبيق الذي يستخدِم <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"التطبيقات التي تستخدِم <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"، "</string>
@@ -927,8 +926,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"إيقاف أجهزة الاستشعار"</string>
<string name="device_services" msgid="1191212554435440592">"خدمات الأجهزة"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"بلا عنوان"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"فتح <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"فتح إعدادات الإشعارات في <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index fbaad96d0454..c782d1be3da9 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 70608a17531d..896fe3408235 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> tətbiq <xliff:g id="TYPE_1">%2$s</xliff:g> tətbiqindən istifadə edir.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Anladım"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Məxfilik ayarları"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"<xliff:g id="TYPES_LIST">%s</xliff:g> tətbiqindən istifadə edən tətbiq"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"<xliff:g id="TYPES_LIST">%s</xliff:g> tətbiqindən istifadə edən tətbiqlər"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensorlar deaktivdir"</string>
<string name="device_services" msgid="1191212554435440592">"Cihaz Xidmətləri"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Başlıq yoxdur"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqini açın"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün bildiriş ayarlarını açın"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 8a754f3425fc..14ab0a4422b0 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -886,8 +886,7 @@
<item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> aplikacija koristi dozvolu <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Važi"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Podešav. privatnosti"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplikacija koja koristi dozvole <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplikacije koje koriste dozvole <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -903,8 +902,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzori su isključeni"</string>
<string name="device_services" msgid="1191212554435440592">"Usluge za uređaje"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Bez naslova"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Otvorite <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Otvorite podešavanja obaveštenja za <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 3390fcbf8ad7..0e724fa02954 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -917,4 +917,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 00454ddda7e3..c44b3ad957ee 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> приложение използва <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Разбрах"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Поверит.: Настройки"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Приложение, което използва <xliff:g id="TYPES_LIST">%s</xliff:g> ви"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Приложения, които използват <xliff:g id="TYPES_LIST">%s</xliff:g> ви"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Сензорите са изключени"</string>
<string name="device_services" msgid="1191212554435440592">"Услуги за устройството"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Няма заглавие"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Отваряне на „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Отваряне на настройките за известията за „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index b864206c6084..ec7ff6d7d110 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index d1528316b0ae..77069b2c4e2b 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -888,8 +888,7 @@
<item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> aplikacija koristi <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Razumijem"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Postavke privatnosti"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplikacija koristi odobrenja <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplikacije koriste odobrenja <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -905,8 +904,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzori su isključeni"</string>
<string name="device_services" msgid="1191212554435440592">"Usluge uređaja"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Bez naslova"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Otvorite aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Otvorite postavke obavijesti za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index f41ea3cd5b83..1c52610722cb 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 4bdc271df52b..735b476a4583 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -915,4 +915,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 0c3c253434da..615338dbcef3 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -879,8 +879,7 @@
<item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> apps anvender din/dit <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privatlivsindstill."</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App, der anvender din/dit <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps, der anvender din/dit <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Deaktiver sensorer"</string>
<string name="device_services" msgid="1191212554435440592">"Enhedstjenester"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Ingen titel"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Åbn <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Åbn notifikationsindstillingerne for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index c21288dbfadc..4e2e1e134905 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -441,7 +441,7 @@
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduzierung der Leistung und Hintergrunddaten"</string>
<string name="battery_saver_notification_action_text" msgid="132118784269455533">"Energiesparmodus deaktivieren"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> nimmt alle auf deinem Bildschirm angezeigten Aktivitäten auf."</string>
- <string name="media_projection_remember_text" msgid="3103510882172746752">"Nicht erneut anzeigen"</string>
+ <string name="media_projection_remember_text" msgid="3103510882172746752">"Nicht mehr anzeigen"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Alle löschen"</string>
<string name="manage_notifications_text" msgid="2386728145475108753">"Verwalten"</string>
<string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"Benachrichtigungen durch \"Bitte nicht stören\" pausiert"</string>
@@ -883,8 +883,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> App verwendet gerade: <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Datenschutzeinst."</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App, die <xliff:g id="TYPES_LIST">%s</xliff:g> verwendet"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps, die <xliff:g id="TYPES_LIST">%s</xliff:g> verwenden"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -899,8 +898,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensoren aus"</string>
<string name="device_services" msgid="1191212554435440592">"Gerätedienste"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Kein Titel"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> öffnen"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Benachrichtigungseinstellungen für <xliff:g id="APP_NAME">%1$s</xliff:g> öffnen"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 23818956b18e..1a0df6bcbda3 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> εφαρμογή χρησιμοποιεί το <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Κατάλαβα"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Ρυθμίσεις απορρήτου"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Εφαρμογή που χρησιμοποιεί τις λειτουργίες <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Εφαρμογές που χρησιμοποιούν τις λειτουργίες <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Αισθητήρες ανενεργοί"</string>
<string name="device_services" msgid="1191212554435440592">"Υπηρεσίες συσκευής"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Χωρίς τίτλο"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Άνοιγμα <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Άνοιγμα ρυθμίσεων ειδοποιήσεων για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 63f677319abd..95c1349b76e4 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> application is using your <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Got it"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privacy settings"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string>
<string name="device_services" msgid="1191212554435440592">"Device Services"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Open <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Open notification settings for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index d6539e7bcd20..6d55c5a6227a 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> application is using your <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Got it"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privacy settings"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string>
<string name="device_services" msgid="1191212554435440592">"Device Services"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Open <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Open notification settings for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 63f677319abd..95c1349b76e4 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> application is using your <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Got it"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privacy settings"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string>
<string name="device_services" msgid="1191212554435440592">"Device Services"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Open <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Open notification settings for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 63f677319abd..95c1349b76e4 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> application is using your <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Got it"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privacy settings"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string>
<string name="device_services" msgid="1191212554435440592">"Device Services"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Open <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Open notification settings for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 36ef6479415e..266faa85f960 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‎‎‏‏‎‎‎‎‎‎‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‎‎‎‎‎‏‎‎‏‏‎<xliff:g id="NUM_APPS_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ application is using your ‎‏‎‎‏‏‎<xliff:g id="TYPE_1">%2$s</xliff:g>‎‏‎‎‏‏‏‎.‎‏‎‎‏‎</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‏‎‏‏‎‏‎‎‎‏‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‎‏‎‏‏‎‏‏‎‎‏‎‎‏‎‎‏‏‎‎‏‎‎‎Got it‎‏‎‎‏‎"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‎‎‏‏‏‎‎‏‏‏‎‎‏‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎Privacy settings‎‏‎‎‏‎"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‏‎‏‎‎‎‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‏‎‎‏‎‎‎‎‎‎‎‎‎‏‎‎‎‏‏‏‏‎‎‎‎App using your ‎‏‎‎‏‏‎<xliff:g id="TYPES_LIST">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‎‏‎‎‏‎‏‎‎‏‎‎‎‎‎‏‏‏‎‎‏‏‏‎‎‏‎‏‎‎‎‎‏‏‏‎‎‎‏‎‏‏‎‎‎‎‎‏‎‏‎Apps using your ‎‏‎‎‏‏‎<xliff:g id="TYPES_LIST">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‎‎‎‏‎‏‎‏‏‎‏‏‎‏‏‏‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‏‏‏‎‎‏‏‏‏‏‏‎, ‎‏‎‎‏‎ "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‎‏‎‎‏‏‎‏‏‎‏‏‎‏‏‏‎‎‏‎‏‎‎‎‏‎‏‏‏‎‎‏‎‎‏‎‏‏‏‏‎‏‎‎‏‏‏‏‏‎‎Sensors off‎‏‎‎‏‎"</string>
<string name="device_services" msgid="1191212554435440592">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‏‎‎‎‎‎‎‎‏‎‎‏‏‎‎‎‎‎‎‏‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‎‎‎‎‎Device Services‎‏‎‎‏‎"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‎‎‎‏‎‎‏‎‎‎‏‏‎‎‎‏‏‎‏‎‏‎‎‏‎‏‏‏‎‎‏‏‎‎‏‏‎‏‏‎No title‎‏‎‎‏‎"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‏‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‏‎‎‎‎‎‎‎‎‏‏‎‏‏‎‎‏‎‏‎Open ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‎‏‏‎‏‎‏‏‏‎‎‎‏‎‏‏‏‎‏‏‎‎‎‎‎‎‎‏‏‏‏‏‎‎‎‏‏‎‏‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎Open notification settings for ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 81cd300fa200..b1f7068b5876 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplicación está usando tu <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Entendido"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Config. privacidad"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Una app está usando tu <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps que están usando tu <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Se desactivaron los sensores"</string>
<string name="device_services" msgid="1191212554435440592">"Servicios del dispositivo"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Sin título"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Abrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Abrir la configuración de notificaciones de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 16c182b97d18..b1947fdc46b7 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index b02e45746eb6..8085224caaee 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> rakendus kasutab üksust <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Selge"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privaatsusseaded"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Rakendus, mis kasutab üksusi <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Rakendused, mis kasutavad üksusi <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Andurid on välja lülitatud"</string>
<string name="device_services" msgid="1191212554435440592">"Seadme teenused"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Pealkiri puudub"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Ava <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Ava rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> märguandeseaded"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index b2d29c12faaf..7f9bffa37c8d 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplikazio ari da <xliff:g id="TYPE_1">%2$s</xliff:g> erabiltzen.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Ados"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Pribatutasun-ezarpenak"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"<xliff:g id="TYPES_LIST">%s</xliff:g> erabiltzen ari den aplikazioa"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"<xliff:g id="TYPES_LIST">%s</xliff:g> erabiltzen ari diren aplikazioak"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sentsoreak desaktibatuta daude"</string>
<string name="device_services" msgid="1191212554435440592">"Gailuetarako zerbitzuak"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Ez du izenik"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Ireki <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Ireki <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren jakinarazpen-ezarpenak"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 4fb889bc2501..018d6d1fd0da 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -879,8 +879,7 @@
<item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> برنامه درحال استفاده از <xliff:g id="TYPE_5">%2$s</xliff:g> شما است.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"متوجه شدم"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"تنظیمات حریم خصوصی"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"برنامه‌ای که از <xliff:g id="TYPES_LIST">%s</xliff:g> شما استفاده می‌کند"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"برنامه‌هایی که از <xliff:g id="TYPES_LIST">%s</xliff:g> شما استفاده می‌کنند"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"، "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"حسگرها خاموش است"</string>
<string name="device_services" msgid="1191212554435440592">"سرویس‌های دستگاه"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"بدون عنوان"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"باز کردن <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"تنظیمات اعلان <xliff:g id="APP_NAME">%1$s</xliff:g> را باز کنید"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 1ab48a0855d5..0258ccbf9332 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="TYPE_1">%2$s</xliff:g> on <xliff:g id="NUM_APPS_0">%1$d</xliff:g> sovelluksen käytössä.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Selvä"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Tietosuoja-asetukset"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Sovellus, jolla on <xliff:g id="TYPES_LIST">%s</xliff:g> ‑käyttöoikeus"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Sovellukset, joilla on <xliff:g id="TYPES_LIST">%s</xliff:g> ‑käyttöoikeus"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Anturit pois päältä"</string>
<string name="device_services" msgid="1191212554435440592">"Laitepalvelut"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Ei nimeä"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Avaa <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Avaa ilmoitusasetukset (<xliff:g id="APP_NAME">%1$s</xliff:g>)"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 554a22253d93..a3a31356fcfc 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 2e4700059fa3..d1ce32e3a193 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 90b9f87a12af..d76c34a64042 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplicación utiliza o teu dispositivo (<xliff:g id="TYPE_1">%2$s</xliff:g>).</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"De acordo"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Config. privacidade"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplicación que utiliza o seguinte: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplicacións que utilizan o seguinte: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Desactivar sensores"</string>
<string name="device_services" msgid="1191212554435440592">"Servizos do dispositivo"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Sen título"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Abre a aplicación <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Abre a configuración de notificacións para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 5717616b706d..c84051cc51bb 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 20b9198e6e21..157f55c9bede 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 79f410a87929..77c3ce3b47b8 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -886,8 +886,7 @@
<item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> aplikacija upotrebljava <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Shvaćam"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Postavke privatnosti"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplikacije koje upotrebljavaju <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplikacije koje upotrebljavaju <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -903,8 +902,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzori su isključeni"</string>
<string name="device_services" msgid="1191212554435440592">"Usluge uređaja"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Bez naslova"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Otvorite aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Otvorite postavke obavijesti za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index d0cdfb4601d6..308295a20cc1 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> alkalmazás használja a következőt: <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Értem"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Adatvédelmi beállítások"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"A következőket használó alkalmazás: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"A következőt használó alkalmazások: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Érzékelők kikapcsolva"</string>
<string name="device_services" msgid="1191212554435440592">"Eszközszolgáltatások"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Nincs cím"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> megnyitása"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> – az alkalmazás értesítési beállításainak megnyitása"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 41bd378e912e..a3e05ad1cc01 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 98e1c4b3d9a3..2bad55e03d62 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplikasi menggunakan <xliff:g id="TYPE_1">%2$s</xliff:g> Anda.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Oke"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Setelan privasi"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplikasi yang menggunakan <xliff:g id="TYPES_LIST">%s</xliff:g> Anda"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplikasi yang menggunakan <xliff:g id="TYPES_LIST">%s</xliff:g> Anda"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensor nonaktif"</string>
<string name="device_services" msgid="1191212554435440592">"Layanan Perangkat"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Tanpa judul"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Buka <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Buka setelan notifikasi untuk <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index d1ea979f5a2e..35026134445e 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -879,8 +879,7 @@
<item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> forrit eru að nota <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Ég skil"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Persónuvernd"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Forrit sem nota <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Forrit sem nota <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Slökkt á skynjurum"</string>
<string name="device_services" msgid="1191212554435440592">"Tækjaþjónusta"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Enginn titill"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Opna <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Opna tilkynningastillingar fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index af22c6d19399..42ff72a59014 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> applicazione sta utilizzando <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Impostazioni privacy"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App che usa <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"App che utilizzano <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensori disattivati"</string>
<string name="device_services" msgid="1191212554435440592">"Servizi del dispositivo"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Senza titolo"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Apri <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Apri le impostazioni di notifica dell\'app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index a7d5138cebb7..036b0dfa7f3b 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -519,9 +519,9 @@
<string name="accessibility_volume_collapse" msgid="3609549593031810875">"כווץ"</string>
<string name="accessibility_output_chooser" msgid="8185317493017988680">"החלפת מכשיר פלט"</string>
<string name="screen_pinning_title" msgid="3273740381976175811">"המסך מוצמד"</string>
- <string name="screen_pinning_description" msgid="8909878447196419623">"נשאר בתצוגה עד לביטול ההצמדה. גע בלחצנים \'הקודם\' ו\'סקירה\' והחזק כדי לבטל את ההצמדה."</string>
+ <string name="screen_pinning_description" msgid="8909878447196419623">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'סקירה\' כדי לבטל את ההצמדה."</string>
<string name="screen_pinning_description_recents_invisible" msgid="8281145542163727971">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'דף הבית\' כדי לבטל את ההצמדה."</string>
- <string name="screen_pinning_description_accessible" msgid="426190689254018656">"נשאר בתצוגה עד לביטול ההצמדה. גע בלחצן \'סקירה\' והחזק כדי לבטל את ההצמדה."</string>
+ <string name="screen_pinning_description_accessible" msgid="426190689254018656">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצן \'סקירה\' כדי לבטל את ההצמדה."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="6134833683151189507">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצן \'דף הבית\' כדי לבטל את ההצמדה."</string>
<string name="screen_pinning_toast" msgid="2266705122951934150">"כדי לבטל את ההצמדה של מסך זה, יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'סקירה\'"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="8252402309499161281">"כדי לבטל את ההצמדה של מסך זה, יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'דף הבית\'"</string>
@@ -915,4 +915,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 9095fd1a8cdd..7aa7fbf39661 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> 個のアプリが <xliff:g id="TYPE_1">%2$s</xliff:g> を使用しています。</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"プライバシー設定"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"<xliff:g id="TYPES_LIST">%s</xliff:g>を使用しているアプリ"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"<xliff:g id="TYPES_LIST">%s</xliff:g>を使用しているアプリ"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"、 "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"センサー OFF"</string>
<string name="device_services" msgid="1191212554435440592">"デバイス サービス"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"タイトルなし"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> を開く"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> の通知設定を開く"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 92368300422a..4fec28473a7f 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one">თქვენი <xliff:g id="TYPE_1">%2$s</xliff:g> გამოიყენება <xliff:g id="NUM_APPS_0">%1$d</xliff:g> აპლიკაციის მიერ.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"გასაგებია"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"კონფიდ. პარამეტრები"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"აპი, რომლის მიერაც გამოიყენება თქვენი <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"აპები, რომელთა მიერაც გამოიყენება თქვენი <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"სენსორების გამორთვა"</string>
<string name="device_services" msgid="1191212554435440592">"მოწყობილობის სერვისები"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"უსათაურო"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის გახსნა"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის შეტყობინების პარამეტრების გახსნა"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 3b46364d8faf..c5022b55cacd 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 6811072ef0ff..c03dddd43ba6 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 273470ada54e..aa0e63f855be 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index ca45e4ddedc6..eb949037461e 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 82d709b52359..14d93e498e8f 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index ed0540780031..467a2dc77b67 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index a136772baad4..c79743ffdbd0 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -893,8 +893,7 @@
<item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> programų naudoja jūsų <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Supratau"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privatumo nustatymai"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Programa, kuri naudoja: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Programos, kurios naudoja: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -911,8 +910,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Jutikliai išjungti"</string>
<string name="device_services" msgid="1191212554435440592">"Įrenginio paslaugos"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Nėra pavadinimo"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Atidaryti „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Atidaryti „<xliff:g id="APP_NAME">%1$s</xliff:g>“ pranešimų nustatymus"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index fec4fe8ca672..d6dc8f34c6dc 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -886,8 +886,7 @@
<item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> lietojumprogrammās tiek izmantots: <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Labi"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Konfidencialitāte"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Lietotne, kurā tiek izmantots: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Lietotnes, kurās tiek izmantots: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -903,8 +902,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensori izslēgti"</string>
<string name="device_services" msgid="1191212554435440592">"Ierīces pakalpojumi"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Nav nosaukuma"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Atvērt lietotni <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Atvērt paziņojumu iestatījumus lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 6b3e8cc111e5..03e31f745794 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 37d4b8c85f96..f25ae1d0e1d8 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 42cb765369b1..0e5dbb71d39a 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one">Таны <xliff:g id="TYPE_1">%2$s</xliff:g>-г <xliff:g id="NUM_APPS_0">%1$d</xliff:g> апп ашиглаж байна.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Ойлголоо"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Нууцлалын тохиргоо"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Апп таны <xliff:g id="TYPES_LIST">%s</xliff:g>-г ашиглаж байна"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Аппууд таны <xliff:g id="TYPES_LIST">%s</xliff:g>-г ашиглаж байна"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Мэдрэгчийг унтраах"</string>
<string name="device_services" msgid="1191212554435440592">"Төхөөрөмжийн үйлчилгээ"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Гарчиггүй"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г нээх"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н мэдэгдлийн тохиргоог нээх"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 44d8c4e8f3ff..1b81062cc247 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index eee6b25bcddf..df10b2ffa438 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index b341bea7d19b..f8278059919d 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -684,7 +684,7 @@
<string name="keyboard_key_numpad_template" msgid="8729216555174634026">"ဂဏန်းကွက်<xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"စနစ်"</string>
<string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ပင်မ"</string>
- <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"မကြာသေးခင်က"</string>
+ <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"လတ်တလော"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"နောက်သို့"</string>
<string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"အကြောင်းကြားချက်များ"</string>
<string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"ကီးဘုတ် ဖြတ်လမ်းများ"</string>
@@ -879,8 +879,7 @@
<item quantity="one">အပလီကေးရှင်း <xliff:g id="NUM_APPS_0">%1$d</xliff:g> ခုက သင်၏ <xliff:g id="TYPE_1">%2$s</xliff:g> ကို အသုံးပြုနေသည်။</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"ရပါပြီ"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"ကန့်သတ်ဆက်တင်များ"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"သင့် <xliff:g id="TYPES_LIST">%s</xliff:g> ကို အသုံးပြုနေသော အက်ပ်"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"သင့် <xliff:g id="TYPES_LIST">%s</xliff:g> ကို အသုံးပြုနေသော အက်ပ်များ"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"၊ "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"အာရုံခံကိရိယာများ ပိတ်ထားသည်"</string>
<string name="device_services" msgid="1191212554435440592">"စက်ပစ္စည်းဝန်ဆောင်မှုများ"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"ခေါင်းစဉ် မရှိပါ"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> ကိုဖွင့်ရန်"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> အတွက် အကြောင်းကြားချက်ဆက်တင်များကို ဖွင့်ရန်"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index a27addba20de..1370468c32e5 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 1bb366481b25..08f3cef84582 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 8075ef4cd6af..7cb4b5a359c0 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -792,7 +792,7 @@
<string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g>-instellingen openen."</string>
<string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Volgorde van instellingen bewerken."</string>
<string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
- <string name="tuner_lock_screen" msgid="5755818559638850294">"Scherm vergrendelen"</string>
+ <string name="tuner_lock_screen" msgid="5755818559638850294">"Vergrendelingsscherm"</string>
<string name="pip_phone_expand" msgid="5889780005575693909">"Uitvouwen"</string>
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimaliseren"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Sluiten"</string>
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> app gebruikt je <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privacyinstellingen"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App die je <xliff:g id="TYPES_LIST">%s</xliff:g> gebruikt"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps die je <xliff:g id="TYPES_LIST">%s</xliff:g> gebruiken"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensoren uit"</string>
<string name="device_services" msgid="1191212554435440592">"Apparaatservices"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Geen titel"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> openen"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Instellingen voor meldingen voor <xliff:g id="APP_NAME">%1$s</xliff:g> openen"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 337b15d219f7..b9b4ea8f8360 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 4d8e3f11ceab..5432975a7320 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index d955236c3b09..b69204593082 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -893,8 +893,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplikacja używa: <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Ustawienia prywatności"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplikacje, które używają: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplikacje, które używają: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -911,8 +910,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Wyłącz czujniki"</string>
<string name="device_services" msgid="1191212554435440592">"Usługi urządzenia"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Bez tytułu"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Otwórz: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Otwórz ustawienia powiadomień z aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index d2219d259522..fcd7f85cf6f4 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -879,8 +879,7 @@
<item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> aplicativos estão usando <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Ok"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Config. de privacidade"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App usando <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps usando <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensores desativados"</string>
<string name="device_services" msgid="1191212554435440592">"Serviços do dispositivo"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Sem título"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Abrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Abra as configurações de notificação do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 0866ffc7acea..6579645c83b9 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplicação está a utilizar o(a) <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Compreendi"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Def. de privacidade"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplicações que utilizam o(a) <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplicações que utilizam o(a) <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensores desativados"</string>
<string name="device_services" msgid="1191212554435440592">"Serviços do dispositivo"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Sem título"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Abrir a aplicação <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Abrir as definições de notificação da aplicação <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index d2219d259522..fcd7f85cf6f4 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -879,8 +879,7 @@
<item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> aplicativos estão usando <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Ok"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Config. de privacidade"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App usando <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps usando <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensores desativados"</string>
<string name="device_services" msgid="1191212554435440592">"Serviços do dispositivo"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Sem título"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Abrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Abra as configurações de notificação do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index e04048458ea6..144bfc38f677 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -886,8 +886,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplicație folosește <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Setări de confidențialitate"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplicație care folosește <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplicații care folosesc <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -903,8 +902,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzori dezactivați"</string>
<string name="device_services" msgid="1191212554435440592">"Servicii pentru dispozitiv"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Fără titlu"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Accesați <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Deschideți setările pentru notificări pentru aplicația <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 338ce14764a0..6d65592ad549 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -893,8 +893,7 @@
<item quantity="other">Функцию \"<xliff:g id="TYPE_5">%2$s</xliff:g>\" используют <xliff:g id="NUM_APPS_4">%1$d</xliff:g> приложения.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"ОК"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Конфиденциальность"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Приложение, в котором используются операции <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Приложения, в которых используются операции <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -911,8 +910,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Датчики отключены"</string>
<string name="device_services" msgid="1191212554435440592">"Сервисы устройства"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Без названия"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Открыть приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Настройки уведомлений приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 3a0b3a4200ba..2529f19370c0 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -879,8 +879,7 @@
<item quantity="other">යෙදුම් <xliff:g id="NUM_APPS_4">%1$d</xliff:g>ක් ඔබේ <xliff:g id="TYPE_5">%2$s</xliff:g> භාවිත කරමින් සිටිති.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"තේරුණා"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"පෞද්ගලිකත්ව සැකසීම්"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"ඔබගේ <xliff:g id="TYPES_LIST">%s</xliff:g> භාවිත කරන යෙදුම්"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"ඔබගේ <xliff:g id="TYPES_LIST">%s</xliff:g> භාවිත කරන යෙදුම්"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"සංවේදක ක්‍රියාවිරහිතයි"</string>
<string name="device_services" msgid="1191212554435440592">"උපාංග සේවා"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"මාතෘකාවක් නැත"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> විවෘත කරන්න"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> සඳහා දැනුම්දීම් සැකසීම් විවෘත කරන්න"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 883243e65496..923384f93511 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -893,8 +893,7 @@
<item quantity="one"><xliff:g id="TYPE_1">%2$s</xliff:g> používa <xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplikácia.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Dobre"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Nastavenia ochrany súkromia"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplikácia používajúca <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplikácie používajúce <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -911,8 +910,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzory sú vypnuté"</string>
<string name="device_services" msgid="1191212554435440592">"Služby zariadenia"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Bez názvu"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Otvoriť <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Otvoriť nastavenia upozornení pre <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index db40b44c4d17..d497f26926de 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -915,4 +915,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index ad6113e74c2b..db905cebb30d 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 768ae7fa2a2d..264698a779b7 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -886,8 +886,7 @@
<item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> апликација користи дозволу <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Важи"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Подешав. приватности"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Апликација која користи дозволе <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Апликације које користе дозволе <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -903,8 +902,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Сензори су искључени"</string>
<string name="device_services" msgid="1191212554435440592">"Услуге за уређаје"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Без наслова"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Отворите <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Отворите подешавања обавештења за <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 0f36517ccce0..7e8446e1a427 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index a11e4d44e1c0..eb658ff17cfb 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index a8587c121815..5bcc6fec7d39 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index a512c0c0adc4..cb9b70d6bbdf 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index b8a840eedaad..6a126ff00684 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one">มี <xliff:g id="NUM_APPS_0">%1$d</xliff:g> แอปพลิเคชันกำลังใช้<xliff:g id="TYPE_1">%2$s</xliff:g></item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"รับทราบ"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"การตั้งค่าความเป็นส่วนตัว"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"มีแอปกำลังใช้<xliff:g id="TYPES_LIST">%s</xliff:g>ของคุณ"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"มีหลายแอปกำลังใช้<xliff:g id="TYPES_LIST">%s</xliff:g>ของคุณ"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"เซ็นเซอร์ปิดอยู่"</string>
<string name="device_services" msgid="1191212554435440592">"บริการของอุปกรณ์"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"ไม่มีชื่อ"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"เปิด <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"เปิดการตั้งค่าการแจ้งเตือนสำหรับ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 72c5eacf806c..1550787b4b27 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -879,8 +879,7 @@
<item quantity="other">Ginagamit ng <xliff:g id="NUM_APPS_4">%1$d</xliff:g> na application ang iyong <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Mga setting ng privacy"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App na gumagamit ng iyong <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Mga app na gumagamit ng iyong <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Naka-off ang mga sensor"</string>
<string name="device_services" msgid="1191212554435440592">"Mga Serbisyo ng Device"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Walang pamagat"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Buksan ang <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Buksan ang mga setting ng notification para sa <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 5cd4e4c5f39f..93671558e3ef 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index b231c581b212..a850f213ca94 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -915,4 +915,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 90447d777794..c7bf3b0e4e0a 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> ایپلیکیشن آپ کی <xliff:g id="TYPE_1">%2$s</xliff:g> کا استعمال کر رہی ہے۔</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"سمجھ آ گئی"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"رازداری کی ترتیبات"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"ایپ آپ کی <xliff:g id="TYPES_LIST">%s</xliff:g> کا استعمال کر رہی ہیں"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"ایپس آپ کی <xliff:g id="TYPES_LIST">%s</xliff:g> کا استعمال کر رہی ہیں"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"، "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"سینسرز آف ہیں"</string>
<string name="device_services" msgid="1191212554435440592">"آلہ کی سروس"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"کوئی عنوان نہیں ہے"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> کھولیں"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے لئے اطلاع کی ترتیبات کھولیں"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 4a7af622bc64..48532fad0c1d 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> ta ilova <xliff:g id="TYPE_1">%2$s</xliff:g> ishlatmoqda.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Maxfiylik sozlama-ri"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"<xliff:g id="TYPES_LIST">%s</xliff:g> ishlatayotgan ilova"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Ilovalar <xliff:g id="TYPES_LIST">%s</xliff:g> ishlatmoqda"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensorlar nofaol"</string>
<string name="device_services" msgid="1191212554435440592">"Qurilma xizmatlari"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Nomsiz"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Ochish: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirishnoma sozlamalarini ochish"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index ad8d17cc23c1..b796503bbf3d 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> ứng dụng đang dùng <xliff:g id="TYPE_1">%2$s</xliff:g> của bạn.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Cài đặt quyền riêng tư"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Ứng dụng đang sử dụng <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Các ứng dụng đang sử dụng <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Tắt cảm biến"</string>
<string name="device_services" msgid="1191212554435440592">"Dịch vụ cho thiết bị"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Không có tiêu đề"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Mở <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Mở mục cài đặt thông báo dành cho <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 0330edf023e0..3a5dd5cda55d 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -899,4 +899,10 @@
<skip />
<!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
<skip />
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
+ <skip />
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 01797fb83fd2..8d67f5c7a5dc 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one">有 <xliff:g id="NUM_APPS_0">%1$d</xliff:g> 個應用程式正在使用您的<xliff:g id="TYPE_1">%2$s</xliff:g>。</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"知道了"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"隱私權設定"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"使用<xliff:g id="TYPES_LIST">%s</xliff:g>的應用程式"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"使用<xliff:g id="TYPES_LIST">%s</xliff:g>的應用程式"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"、 "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"感應器已關閉"</string>
<string name="device_services" msgid="1191212554435440592">"裝置服務"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"無標題"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"開啟「<xliff:g id="APP_NAME">%1$s</xliff:g>」"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"開啟「<xliff:g id="APP_NAME">%1$s</xliff:g>」的通知設定"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 62b7cb667937..d8d0c07bcbc0 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -879,8 +879,7 @@
<item quantity="one">有 <xliff:g id="NUM_APPS_0">%1$d</xliff:g> 個應用程式正在使用你的<xliff:g id="TYPE_1">%2$s</xliff:g>。</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"我知道了"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"隱私權設定"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"使用<xliff:g id="TYPES_LIST">%s</xliff:g>的應用程式"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"使用<xliff:g id="TYPES_LIST">%s</xliff:g>的應用程式"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"、 "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"已關閉感應器"</string>
<string name="device_services" msgid="1191212554435440592">"裝置服務"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"無標題"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"開啟「<xliff:g id="APP_NAME">%1$s</xliff:g>」"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"開啟「<xliff:g id="APP_NAME">%1$s</xliff:g>」的通知設定"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index f8bf2e39d748..2e0efcc863c7 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -879,8 +879,7 @@
<item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> izinhlelo zokusebenza zisebenzisa i-<xliff:g id="TYPE_5">%2$s</xliff:g> yakho.</item>
</plurals>
<string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Ngiyezwa"</string>
- <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
- <skip />
+ <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Izilungiselelo zobumfihlo"</string>
<string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Uhlelo lokusebenza olusebenzisa i-<xliff:g id="TYPES_LIST">%s</xliff:g> yakho"</string>
<string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Izinhlelo zokusebenza ezisebenzisa i-<xliff:g id="TYPES_LIST">%s</xliff:g> yakho"</string>
<string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
<string name="sensor_privacy_mode" msgid="8982771253020769598">"Izinzwa zivaliwe"</string>
<string name="device_services" msgid="1191212554435440592">"Amasevisi edivayisi"</string>
<string name="music_controls_no_title" msgid="5236895307087002011">"Asikho isihloko"</string>
- <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+ <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Vula i-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubbles_settings_button_description" msgid="1940331766151865776">"VUla izilungiselelo zesaziso ze-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+ <skip />
+ <!-- no translation found for no_bubbles (7173621233904687258) -->
<skip />
- <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+ <!-- no translation found for yes_bubbles (668809525728633841) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 03445352e330..1e1245fe0d86 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -967,7 +967,7 @@
<!-- Height and width of App Opp icons in Ongoing App Ops dialog -->
<dimen name="ongoing_appops_dialog_icon_size">24dp</dimen>
<!-- Left margin of App Opp icons in Ongoing App Ops dialog -->
- <dimen name="ongoing_appops_dialog_icon_margin">8dp</dimen>
+ <dimen name="ongoing_appops_dialog_icon_margin">12dp</dimen>
<!-- Height and width of Application icons in Ongoing App Ops dialog -->
<dimen name="ongoing_appops_dialog_app_icon_size">32dp</dimen>
<!-- Height and width of Plus sign in Ongoing App Ops dialog -->
@@ -988,12 +988,14 @@
<dimen name="ongoing_appops_chip_side_padding">6dp</dimen>
<!-- Padding between background of Ongoing App Ops chip and content -->
<dimen name="ongoing_appops_chip_bg_padding">0dp</dimen>
- <!-- Margin between icons of Ongoing App Ops chip -->
- <dimen name="ongoing_appops_chip_icon_margin">4dp</dimen>
+ <!-- Margin between icons of Ongoing App Ops chip when QQS-->
+ <dimen name="ongoing_appops_chip_icon_margin_collapsed">0dp</dimen>
+ <!-- Margin between icons of Ongoing App Ops chip when QS-->
+ <dimen name="ongoing_appops_chip_icon_margin_expanded">8dp</dimen>
<!-- Icon size of Ongoing App Ops chip -->
<dimen name="ongoing_appops_chip_icon_size">18dp</dimen>
<!-- Radius of Ongoing App Ops chip corners -->
- <dimen name="ongoing_appops_chip_bg_corner_radius">12dp</dimen>
+ <dimen name="ongoing_appops_chip_bg_corner_radius">4dp</dimen>
<!-- Text size for Ongoing App Ops dialog title -->
<dimen name="ongoing_appops_dialog_title_size">20sp</dimen>
<!-- Text size for Ongoing App Ops dialog items -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index db4a6cc1d704..b4131d738d13 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -955,6 +955,9 @@
<!-- Interruption level: Alarms only. Optimized for narrow two-line display. [CHAR LIMIT=40] -->
<string name="interruption_level_alarms_twoline">Alarms\nonly</string>
+ <!-- Indication on the keyguard that is shown when the device is wirelessly charging. [CHAR LIMIT=80]-->
+ <string name="keyguard_indication_charging_time_wireless"><xliff:g id="percentage" example="20%">%2$s</xliff:g> • Wirelessly Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%1$s</xliff:g> until full)</string>
+
<!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=50]-->
<string name="keyguard_indication_charging_time"><xliff:g id="percentage">%2$s</xliff:g> • Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%1$s</xliff:g> until full)</string>
@@ -1573,12 +1576,18 @@
<string name="inline_blocking_helper">You usually dismiss these notifications.
\nKeep showing them?</string>
+ <!-- Notification Inline controls: button to dismiss the blocking helper [CHAR_LIMIT=25] -->
+ <string name="inline_done_button">Done</string>
+
<!-- Notification Inline controls: continue receiving notifications prompt, channel level -->
<string name="inline_keep_showing">Keep showing these notifications?</string>
<!-- Notification inline controls: block notifications button -->
<string name="inline_stop_button">Stop notifications</string>
+ <!-- Notification inline controls: button to deliver notifications silently from this channel [CHAR_LIMIT=35] -->
+ <string name="inline_deliver_silently_button">Deliver Silently</string>
+
<!-- Notification inline controls: button to block notifications from this channel [CHAR_LIMIT=35] -->
<string name="inline_block_button">Block</string>
@@ -2301,6 +2310,9 @@
<!-- Content description for ongoing privacy chip. Use with multiple apps [CHAR LIMIT=NONE]-->
<string name="ongoing_privacy_chip_content_multiple_apps">Applications are using your <xliff:g id="types_list" example="camera, location">%s</xliff:g>.</string>
+ <!-- Ongoing Privacy "Chip" in use text [CHAR LIMIT=10]-->
+ <string name="ongoing_privacy_chip_in_use">In use:</string>
+
<!-- Content description for ongoing privacy chip. Use with multiple apps using same app op[CHAR LIMIT=NONE]-->
<plurals name="ongoing_privacy_chip_content_multiple_apps_single_op">
<item quantity="one"><xliff:g id="num_apps" example="1">%1$d</xliff:g> application is using your <xliff:g id="type" example="camera">%2$s</xliff:g>.</item>
@@ -2311,7 +2323,7 @@
<!-- Action for accepting the Ongoing privacy dialog [CHAR LIMIT=10]-->
<string name="ongoing_privacy_dialog_ok">Got it</string>
- <!-- Action on Ongoing Privacy Dialog to open privacy hub [CHAR LIMIT=20]-->
+ <!-- Action on Ongoing Privacy Dialog to open privacy hub [CHAR LIMIT=23]-->
<string name="ongoing_privacy_dialog_open_settings">Privacy settings</string>
<!-- Text for item in Ongoing Privacy Dialog title when only one app is using app ops [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index 2ff98ba8ab30..37abab9f1ddb 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -16,19 +16,32 @@
package com.android.systemui.shared.recents;
+import android.graphics.Region;
+import android.os.Bundle;
import android.view.MotionEvent;
import com.android.systemui.shared.recents.ISystemUiProxy;
oneway interface IOverviewProxy {
- void onBind(in ISystemUiProxy sysUiProxy);
+
+ void onActiveNavBarRegionChanges(in Region activeRegion) = 11;
+
+ void onInitialize(in Bundle params) = 12;
+
+
+ /**
+ * @deprecated
+ */
+ void onBind(in ISystemUiProxy sysUiProxy) = 0;
/**
* Called once immediately prior to the first onMotionEvent() call, providing a hint to the
* target the initial source of the subsequent motion events.
*
* @param downHitTarget is one of the {@link NavigationBarCompat.HitTarget}s
+ *
+ * @deprecated
*/
- void onPreMotionEvent(int downHitTarget);
+ void onPreMotionEvent(int downHitTarget) = 1;
/**
* Proxies motion events from the nav bar in SystemUI to the OverviewProxyService. The sender
@@ -38,40 +51,48 @@ oneway interface IOverviewProxy {
* Quick scrub: DOWN, (MOVE/POINTER_DOWN/POINTER_UP)*, SCRUB_START, SCRUB_PROGRESS*, SCRUB_END
*
* Once quick scrub is sent, then no further motion events will be provided.
+ *
+ * @deprecated
*/
- void onMotionEvent(in MotionEvent event);
+ void onMotionEvent(in MotionEvent event) = 2;
/**
* Sent when the user starts to actively scrub the nav bar to switch tasks. Once this event is
* sent the caller will stop sending any motion events and will no longer preemptively cancel
* any recents animations started as a part of the motion event handling.
+ *
+ * @deprecated
*/
- void onQuickScrubStart();
+ void onQuickScrubStart() = 3;
/**
* Sent when the user stops actively scrubbing the nav bar to switch tasks.
+ *
+ * @deprecated
*/
- void onQuickScrubEnd();
+ void onQuickScrubEnd() = 4;
/**
* Sent for each movement over the nav bar while the user is scrubbing it to switch tasks.
+ *
+ * @deprecated
*/
- void onQuickScrubProgress(float progress);
+ void onQuickScrubProgress(float progress) = 5;
/**
* Sent when overview button is pressed to toggle show/hide of overview.
*/
- void onOverviewToggle();
+ void onOverviewToggle() = 6;
/**
* Sent when overview is to be shown.
*/
- void onOverviewShown(boolean triggeredFromAltTab);
+ void onOverviewShown(boolean triggeredFromAltTab) = 7;
/**
* Sent when overview is to be hidden.
*/
- void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
+ void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) = 8;
/**
* Sent when a user swipes up over the navigation bar to launch overview. Swipe up is determined
@@ -83,11 +104,13 @@ oneway interface IOverviewProxy {
* visible, this event will still be sent if user swipes up). When this signal is sent,
* navigation bar will not handle any gestures such as quick scrub and the home button will
* cancel (long) press.
+ *
+ * @deprecated
*/
- void onQuickStep(in MotionEvent event);
+ void onQuickStep(in MotionEvent event) = 9;
/**
* Sent when there was an action on one of the onboarding tips view.
*/
- void onTip(int actionType, int viewType);
+ void onTip(int actionType, int viewType) = 10;
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputChannelCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputChannelCompat.java
index f7ccb816b675..804f4f112c14 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputChannelCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputChannelCompat.java
@@ -16,6 +16,7 @@
package com.android.systemui.shared.system;
+import android.os.Bundle;
import android.os.Looper;
import android.util.Pair;
import android.view.BatchedInputEventReceiver;
@@ -53,6 +54,16 @@ public class InputChannelCompat {
}
/**
+ * Creates a dispatcher from the extras received as part on onInitialize
+ */
+ public static InputEventReceiver fromBundle(Bundle params, String key,
+ Looper looper, Choreographer choreographer, InputEventListener listener) {
+
+ InputChannel channel = params.getParcelable(key);
+ return new InputEventReceiver(channel, looper, choreographer, listener);
+ }
+
+ /**
* @see BatchedInputEventReceiver
*/
public static class InputEventReceiver {
@@ -90,7 +101,7 @@ public class InputChannelCompat {
private final InputChannel mInputChannel;
private final InputEventSender mSender;
- private InputEventDispatcher(InputChannel inputChannel, Looper looper) {
+ public InputEventDispatcher(InputChannel inputChannel, Looper looper) {
mInputChannel = inputChannel;
mSender = new InputEventSender(inputChannel, looper) { };
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
index 69aea2c59029..b363b4a242e1 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
@@ -17,31 +17,15 @@
package com.android.systemui.shared.system;
import android.annotation.IntDef;
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.DisplayMetrics;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-public class NavigationBarCompat {
- /**
- * Touch slopes and thresholds for quick step operations. Drag slop is the point where the
- * home button press/long press over are ignored and will start to drag when exceeded and the
- * touch slop is when the respected operation will occur when exceeded. Touch slop must be
- * larger than the drag slop.
- */
- public static int getQuickStepDragSlopPx() {
- return convertDpToPixel(10);
- }
-
- public static int getQuickStepTouchSlopPx() {
- return convertDpToPixel(24);
- }
+/**
+ * TODO: Remove this class
+ */
+public class NavigationBarCompat extends QuickStepContract {
- public static int getQuickScrubTouchSlopPx() {
- return convertDpToPixel(24);
- }
@Retention(RetentionPolicy.SOURCE)
@IntDef({HIT_TARGET_NONE, HIT_TARGET_BACK, HIT_TARGET_HOME, HIT_TARGET_OVERVIEW})
@@ -75,8 +59,4 @@ public class NavigationBarCompat {
* Interaction type: show/hide the overview button while this service is connected to launcher
*/
public static final int FLAG_SHOW_OVERVIEW_BUTTON = 0x4;
-
- private static int convertDpToPixel(float dp){
- return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
- }
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
new file mode 100644
index 000000000000..6d7abd089861
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.system;
+
+import android.content.res.Resources;
+
+/**
+ * Various shared constants between Launcher and SysUI as part of quickstep
+ */
+public class QuickStepContract {
+
+ public static final String KEY_EXTRA_SYSUI_PROXY = "extra_sysui_proxy";
+ public static final String KEY_EXTRA_INPUT_CHANNEL = "extra_input_channel";
+ public static final String KEY_EXTRA_WINDOW_CORNER_RADIUS = "extra_window_corner_radius";
+ public static final String KEY_EXTRA_SUPPORTS_WINDOW_CORNERS = "extra_supports_window_corners";
+
+ /**
+ * Touch slopes and thresholds for quick step operations. Drag slop is the point where the
+ * home button press/long press over are ignored and will start to drag when exceeded and the
+ * touch slop is when the respected operation will occur when exceeded. Touch slop must be
+ * larger than the drag slop.
+ */
+ public static int getQuickStepDragSlopPx() {
+ return convertDpToPixel(10);
+ }
+
+ public static int getQuickStepTouchSlopPx() {
+ return convertDpToPixel(24);
+ }
+
+ public static int getQuickScrubTouchSlopPx() {
+ return convertDpToPixel(24);
+ }
+
+ private static int convertDpToPixel(float dp) {
+ return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 6c970c0cc814..8de84bf4e2af 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -1,9 +1,19 @@
package com.android.keyguard;
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
+import android.app.WallpaperManager;
import android.content.Context;
import android.graphics.Paint;
import android.graphics.Paint.Style;
+import android.transition.ChangeBounds;
+import android.transition.Transition;
+import android.transition.TransitionManager;
+import android.transition.TransitionValues;
import android.util.AttributeSet;
+import android.util.MathUtils;
+import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -12,8 +22,11 @@ import android.widget.TextClock;
import androidx.annotation.VisibleForTesting;
+import com.android.internal.colorextraction.ColorExtractor;
import com.android.keyguard.clock.ClockManager;
import com.android.systemui.Dependency;
+import com.android.systemui.Interpolators;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
@@ -25,6 +38,7 @@ import java.util.TimeZone;
*/
public class KeyguardClockSwitch extends RelativeLayout {
+ private final Transition mTransition;
/**
* Optional/alternative clock injected via plugin.
*/
@@ -50,6 +64,12 @@ public class KeyguardClockSwitch extends RelativeLayout {
* Maintain state so that a newly connected plugin can be initialized.
*/
private float mDarkAmount;
+ /**
+ * If the Keyguard Slice has a header (big center-aligned text.)
+ */
+ private boolean mShowingHeader;
+ private boolean mSupportsDarkText;
+ private int[] mColorPalette;
private final StatusBarStateController.StateListener mStateListener =
new StatusBarStateController.StateListener() {
@@ -72,12 +92,28 @@ public class KeyguardClockSwitch extends RelativeLayout {
private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
+ /**
+ * Listener for changes to the color palette.
+ *
+ * The color palette changes when the wallpaper is changed.
+ */
+ private SysuiColorExtractor.OnColorsChangedListener mColorsListener = (extractor, which) -> {
+ if ((which & WallpaperManager.FLAG_LOCK) != 0) {
+ if (extractor instanceof SysuiColorExtractor) {
+ updateColors((SysuiColorExtractor) extractor);
+ } else {
+ updateColors(Dependency.get(SysuiColorExtractor.class));
+ }
+ }
+ };
+
public KeyguardClockSwitch(Context context) {
this(context, null);
}
public KeyguardClockSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
+ mTransition = new ClockBoundsTransition();
}
/**
@@ -100,6 +136,9 @@ public class KeyguardClockSwitch extends RelativeLayout {
super.onAttachedToWindow();
Dependency.get(ClockManager.class).addOnClockChangedListener(mClockChangedListener);
Dependency.get(StatusBarStateController.class).addCallback(mStateListener);
+ SysuiColorExtractor colorExtractor = Dependency.get(SysuiColorExtractor.class);
+ colorExtractor.addOnColorsChangedListener(mColorsListener);
+ updateColors(colorExtractor);
}
@Override
@@ -107,6 +146,8 @@ public class KeyguardClockSwitch extends RelativeLayout {
super.onDetachedFromWindow();
Dependency.get(ClockManager.class).removeOnClockChangedListener(mClockChangedListener);
Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
+ Dependency.get(SysuiColorExtractor.class)
+ .removeOnColorsChangedListener(mColorsListener);
}
private void setClockPlugin(ClockPlugin plugin) {
@@ -149,6 +190,9 @@ public class KeyguardClockSwitch extends RelativeLayout {
mClockPlugin.setStyle(getPaint().getStyle());
mClockPlugin.setTextColor(getCurrentTextColor());
mClockPlugin.setDarkAmount(mDarkAmount);
+ if (mColorPalette != null) {
+ mClockPlugin.setColorPalette(mSupportsDarkText, mColorPalette);
+ }
}
/**
@@ -159,7 +203,9 @@ public class KeyguardClockSwitch extends RelativeLayout {
View bigClockView = mClockPlugin.getBigClockView();
if (bigClockView != null) {
container.addView(bigClockView);
- container.setVisibility(View.VISIBLE);
+ if (container.getVisibility() == View.GONE) {
+ container.setVisibility(View.VISIBLE);
+ }
}
}
mBigClockContainer = container;
@@ -246,6 +292,36 @@ public class KeyguardClockSwitch extends RelativeLayout {
}
}
+ private void updateColors(SysuiColorExtractor colorExtractor) {
+ ColorExtractor.GradientColors colors = colorExtractor.getColors(WallpaperManager.FLAG_LOCK,
+ true);
+ mSupportsDarkText = colors.supportsDarkText();
+ mColorPalette = colors.getColorPalette();
+ if (mClockPlugin != null) {
+ mClockPlugin.setColorPalette(mSupportsDarkText, mColorPalette);
+ }
+ }
+
+ /**
+ * Sets if the keyguard slice is showing a center-aligned header. We need a smaller clock
+ * in these cases.
+ */
+ public void setKeyguardShowingHeader(boolean hasHeader) {
+ if (mShowingHeader == hasHeader || hasCustomClock()) {
+ return;
+ }
+ mShowingHeader = hasHeader;
+
+ TransitionManager.beginDelayedTransition((ViewGroup) mClockView.getParent(), mTransition);
+ int fontSize = mContext.getResources().getDimensionPixelSize(mShowingHeader
+ ? R.dimen.widget_small_font_size : R.dimen.widget_big_font_size);
+ int paddingBottom = mContext.getResources().getDimensionPixelSize(mShowingHeader
+ ? R.dimen.widget_vertical_padding_clock : R.dimen.header_subtitle_padding);
+ mClockView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize);
+ mClockView.setPadding(mClockView.getPaddingLeft(), mClockView.getPaddingTop(),
+ mClockView.getPaddingRight(), paddingBottom);
+ }
+
@VisibleForTesting (otherwise = VisibleForTesting.NONE)
ClockManager.ClockChangedListener getClockChangedListener() {
return mClockChangedListener;
@@ -255,4 +331,54 @@ public class KeyguardClockSwitch extends RelativeLayout {
StatusBarStateController.StateListener getStateListener() {
return mStateListener;
}
+
+ /**
+ * Special layout transition that scales the clock view as its bounds change, to make it look
+ * like the text is shrinking.
+ */
+ private class ClockBoundsTransition extends ChangeBounds {
+
+ ClockBoundsTransition() {
+ setDuration(KeyguardSliceView.DEFAULT_ANIM_DURATION / 2);
+ setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+ }
+
+ @Override
+ public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ Animator animator = super.createAnimator(sceneRoot, startValues, endValues);
+ if (animator == null || startValues.view != mClockView) {
+ return animator;
+ }
+
+ ValueAnimator boundsAnimator = null;
+ if (animator instanceof AnimatorSet) {
+ Animator first = ((AnimatorSet) animator).getChildAnimations().get(0);
+ if (first instanceof ValueAnimator) {
+ boundsAnimator = (ValueAnimator) first;
+ }
+ } else if (animator instanceof ValueAnimator) {
+ boundsAnimator = (ValueAnimator) animator;
+ }
+
+ if (boundsAnimator != null) {
+ float bigFontSize = mContext.getResources()
+ .getDimensionPixelSize(R.dimen.widget_big_font_size);
+ float smallFontSize = mContext.getResources()
+ .getDimensionPixelSize(R.dimen.widget_small_font_size);
+ float startScale = mShowingHeader
+ ? bigFontSize / smallFontSize : smallFontSize / bigFontSize;
+ boundsAnimator.addUpdateListener(animation -> {
+ float scale = MathUtils.lerp(startScale, 1f /* stop */,
+ animation.getAnimatedFraction());
+ mClockView.setPivotX(mClockView.getWidth() / 2);
+ mClockView.setPivotY(0);
+ mClockView.setScaleX(scale);
+ mClockView.setScaleY(scale);
+ });
+ }
+
+ return animator;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index bac7844c024b..2040a76b61d3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -37,10 +37,10 @@ import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
-import android.view.ViewGroup;
import android.view.animation.Animation;
import android.widget.Button;
import android.widget.LinearLayout;
+import android.widget.TextView;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
@@ -58,6 +58,7 @@ import com.android.internal.graphics.ColorUtils;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
+import com.android.systemui.R;
import com.android.systemui.keyguard.KeyguardSliceProvider;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;
@@ -78,6 +79,8 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
private final HashMap<View, PendingIntent> mClickActions;
private Uri mKeyguardSliceUri;
+ @VisibleForTesting
+ TextView mTitle;
private Row mRow;
private int mTextColor;
private float mDarkAmount = 0;
@@ -91,6 +94,8 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
private Runnable mContentChangeListener;
private Slice mSlice;
private boolean mHasHeader;
+ private final int mRowWithHeaderPadding;
+ private final int mRowPadding;
public KeyguardSliceView(Context context) {
this(context, null, 0);
@@ -107,6 +112,9 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
tunerService.addTunable(this, Settings.Secure.KEYGUARD_SLICE_URI);
mClickActions = new HashMap<>();
+ mRowPadding = context.getResources().getDimensionPixelSize(R.dimen.subtitle_clock_padding);
+ mRowWithHeaderPadding = context.getResources()
+ .getDimensionPixelSize(R.dimen.header_subtitle_padding);
LayoutTransition transition = new LayoutTransition();
transition.setStagger(LayoutTransition.CHANGE_APPEARING, DEFAULT_ANIM_DURATION / 2);
@@ -117,13 +125,13 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
transition.setInterpolator(LayoutTransition.APPEARING, Interpolators.FAST_OUT_SLOW_IN);
transition.setInterpolator(LayoutTransition.DISAPPEARING, Interpolators.ALPHA_OUT);
transition.setAnimateParentHierarchy(false);
- transition.addTransitionListener(new SliceViewTransitionListener());
setLayoutTransition(transition);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mTitle = findViewById(R.id.title);
mRow = findViewById(R.id.row);
mTextColor = Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor);
mIconSize = (int) mContext.getResources().getDimension(R.dimen.widget_icon_size);
@@ -160,6 +168,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
private void showSlice() {
Trace.beginSection("KeyguardSliceView#showSlice");
if (mSlice == null) {
+ mTitle.setVisibility(GONE);
mRow.setVisibility(GONE);
mHasHeader = false;
if (mContentChangeListener != null) {
@@ -170,8 +179,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
ListContent lc = new ListContent(getContext(), mSlice);
SliceContent headerContent = lc.getHeader();
- mHasHeader = headerContent != null
- && !headerContent.getSliceItem().hasHint(HINT_LIST_ITEM);
+ mHasHeader = headerContent != null && !headerContent.getSliceItem().hasHint(HINT_LIST_ITEM);
List<SliceContent> subItems = new ArrayList<>();
for (int i = 0; i < lc.getRowItems().size(); i++) {
SliceContent subItem = lc.getRowItems().get(i);
@@ -181,12 +189,26 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
subItems.add(subItem);
}
}
+ if (!mHasHeader) {
+ mTitle.setVisibility(GONE);
+ } else {
+ mTitle.setVisibility(VISIBLE);
+
+ RowContent header = lc.getHeader();
+ SliceItem mainTitle = header.getTitleItem();
+ CharSequence title = mainTitle != null ? mainTitle.getText() : null;
+ mTitle.setText(title);
+ }
mClickActions.clear();
final int subItemsCount = subItems.size();
final int blendedColor = getTextColor();
final int startIndex = mHasHeader ? 1 : 0; // First item is header; skip it
mRow.setVisibility(subItemsCount > 0 ? VISIBLE : GONE);
+ LinearLayout.LayoutParams layoutParams = (LayoutParams) mRow.getLayoutParams();
+ layoutParams.topMargin = mHasHeader ? mRowWithHeaderPadding : mRowPadding;
+ mRow.setLayoutParams(layoutParams);
+
for (int i = startIndex; i < subItemsCount; i++) {
RowContent rc = (RowContent) subItems.get(i);
SliceItem item = rc.getSliceItem();
@@ -250,6 +272,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
private void updateTextColors() {
final int blendedColor = getTextColor();
+ mTitle.setTextColor(blendedColor);
int childCount = mRow.getChildCount();
for (int i = 0; i < childCount; i++) {
View v = mRow.getChildAt(i);
@@ -294,7 +317,10 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
setupUri(newValue);
}
- private void setupUri(String uriString) {
+ /**
+ * Sets the slice provider Uri.
+ */
+ public void setupUri(String uriString) {
if (uriString == null) {
uriString = KeyguardSliceProvider.KEYGUARD_SLICE_URI;
}
@@ -512,29 +538,4 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
}
}
}
-
- private class SliceViewTransitionListener implements LayoutTransition.TransitionListener {
- @Override
- public void startTransition(LayoutTransition transition, ViewGroup container, View view,
- int transitionType) {
- switch (transitionType) {
- case LayoutTransition.APPEARING:
- int translation = getResources().getDimensionPixelSize(
- R.dimen.pulsing_notification_appear_translation);
- view.setTranslationY(translation);
- view.animate()
- .translationY(0)
- .setDuration(DEFAULT_ANIM_DURATION)
- .setInterpolator(Interpolators.ALPHA_IN)
- .start();
- break;
- }
- }
-
- @Override
- public void endTransition(LayoutTransition transition, ViewGroup container, View view,
- int transitionType) {
-
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index bb549ada6830..b0670fd0a91a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -16,14 +16,11 @@
package com.android.keyguard;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
-import android.graphics.Paint;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
@@ -37,15 +34,12 @@ import android.util.Slog;
import android.util.TypedValue;
import android.view.View;
import android.widget.GridLayout;
-import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.core.graphics.ColorUtils;
import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.ViewClippingUtil;
import com.android.systemui.Dependency;
-import com.android.systemui.Interpolators;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.google.android.collect.Sets;
@@ -54,14 +48,13 @@ import java.util.Locale;
import java.util.TimeZone;
public class KeyguardStatusView extends GridLayout implements
- ConfigurationController.ConfigurationListener, View.OnLayoutChangeListener {
+ ConfigurationController.ConfigurationListener {
private static final boolean DEBUG = KeyguardConstants.DEBUG;
private static final String TAG = "KeyguardStatusView";
private static final int MARQUEE_DELAY_MS = 2000;
private final LockPatternUtils mLockPatternUtils;
private final IActivityManager mIActivityManager;
- private final float mSmallClockScale;
private TextView mLogoutView;
private KeyguardClockSwitch mClockView;
@@ -74,8 +67,6 @@ public class KeyguardStatusView extends GridLayout implements
private boolean mPulsing;
private float mDarkAmount = 0;
private int mTextColor;
- private int mLastLayoutHeight;
- private int mSmallClockPadding;
private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
@@ -135,8 +126,6 @@ public class KeyguardStatusView extends GridLayout implements
mIActivityManager = ActivityManager.getService();
mLockPatternUtils = new LockPatternUtils(getContext());
mHandler = new Handler(Looper.myLooper());
- mSmallClockScale = getResources().getDimension(R.dimen.widget_small_font_size)
- / getResources().getDimension(R.dimen.widget_big_font_size);
onDensityOrFontScaleChanged();
}
@@ -189,9 +178,6 @@ public class KeyguardStatusView extends GridLayout implements
mVisibleInDoze = Sets.newArraySet(mClockView, mKeyguardSlice);
mTextColor = mClockView.getCurrentTextColor();
- int clockStroke = getResources().getDimensionPixelSize(R.dimen.widget_small_font_stroke);
- mClockView.getPaint().setStrokeWidth(clockStroke);
- mClockView.addOnLayoutChangeListener(this);
mKeyguardSlice.setContentChangeListener(this::onSliceContentChanged);
onSliceContentChanged();
@@ -207,72 +193,20 @@ public class KeyguardStatusView extends GridLayout implements
* Moves clock, adjusting margins when slice content changes.
*/
private void onSliceContentChanged() {
- LinearLayout.LayoutParams layoutParams =
- (LinearLayout.LayoutParams) mClockView.getLayoutParams();
- layoutParams.bottomMargin = mKeyguardSlice.hasHeader() ? mSmallClockPadding : 0;
- mClockView.setLayoutParams(layoutParams);
- }
-
- /**
- * Animate clock when necessary.
- */
- @Override
- public void onLayoutChange(View view, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- boolean smallClock = mKeyguardSlice.hasHeader();
- int heightOffset = smallClock ? 0 : getHeight() - mLastLayoutHeight;
- long duration = KeyguardSliceView.DEFAULT_ANIM_DURATION;
- long delay = smallClock ? 0 : duration / 4;
-
- boolean shouldAnimate = mKeyguardSlice.getLayoutTransition() != null
- && mKeyguardSlice.getLayoutTransition().isRunning();
- if (view == mClockView) {
- float clockScale = smallClock ? mSmallClockScale : 1;
- Paint.Style style = smallClock ? Paint.Style.FILL_AND_STROKE : Paint.Style.FILL;
- mClockView.animate().cancel();
- if (shouldAnimate) {
- mClockView.setY(oldTop + heightOffset);
- mClockView.animate()
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .setDuration(duration)
- .setListener(new ClipChildrenAnimationListener())
- .setStartDelay(delay)
- .y(top)
- .scaleX(clockScale)
- .scaleY(clockScale)
- .withEndAction(() -> {
- mClockView.setStyle(style);
- mClockView.invalidate();
- })
- .start();
- } else {
- mClockView.setY(top);
- mClockView.setScaleX(clockScale);
- mClockView.setScaleY(clockScale);
- mClockView.setStyle(style);
- mClockView.invalidate();
- }
- }
+ mClockView.setKeyguardShowingHeader(mKeyguardSlice.hasHeader());
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- mClockView.setPivotX(mClockView.getWidth() / 2);
- mClockView.setPivotY(0);
- mLastLayoutHeight = getHeight();
layoutOwnerInfo();
}
@Override
public void onDensityOrFontScaleChanged() {
- mSmallClockPadding = getResources()
- .getDimensionPixelSize(R.dimen.widget_small_clock_padding);
if (mClockView != null) {
mClockView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimensionPixelSize(R.dimen.widget_big_font_size));
- mClockView.getPaint().setStrokeWidth(
- getResources().getDimensionPixelSize(R.dimen.widget_small_font_stroke));
}
if (mOwnerInfo != null) {
mOwnerInfo.setTextSize(TypedValue.COMPLEX_UNIT_PX,
@@ -461,24 +395,4 @@ public class KeyguardStatusView extends GridLayout implements
Log.e(TAG, "Failed to logout user", re);
}
}
-
- private class ClipChildrenAnimationListener extends AnimatorListenerAdapter implements
- ViewClippingUtil.ClippingParameters {
-
- ClipChildrenAnimationListener() {
- ViewClippingUtil.setClippingDeactivated(mClockView, true /* deactivated */,
- this /* clippingParams */);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- ViewClippingUtil.setClippingDeactivated(mClockView, false /* deactivated */,
- this /* clippingParams */);
- }
-
- @Override
- public boolean shouldFinish(View view) {
- return view == getParent();
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
index db6127f1d573..3114708de038 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
@@ -89,7 +89,17 @@ public class BubbleClockController implements ClockPlugin {
@Override
public void setTextColor(int color) {
mLockClock.setTextColor(color);
- mDigitalClock.setTextColor(color);
+ }
+
+ @Override
+ public void setColorPalette(boolean supportsDarkText, int[] colorPalette) {
+ if (colorPalette == null || colorPalette.length == 0) {
+ return;
+ }
+ final int length = colorPalette.length;
+ mDigitalClock.setTextColor(colorPalette[Math.max(0, length - 6)]);
+ mAnalogClock.setClockColors(colorPalette[Math.max(0, length - 6)],
+ colorPalette[Math.max(0, length - 3)]);
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
index 3591dc82c8ec..4d8cf963ff50 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
@@ -22,6 +22,7 @@ import android.content.res.Resources;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
+import android.widget.FrameLayout.LayoutParams;
import com.android.keyguard.R;
@@ -80,8 +81,9 @@ public class ClockLayout extends FrameLayout {
// Put digital clock in two left corner of the screen.
if (mDigitalClock != null) {
- mDigitalClock.setX(0.1f * getWidth() + offsetX);
- mDigitalClock.setY(0.1f * getHeight() + offsetY);
+ LayoutParams params = (LayoutParams) mDigitalClock.getLayoutParams();
+ mDigitalClock.setX(offsetX + params.leftMargin);
+ mDigitalClock.setY(offsetY + params.topMargin);
}
// Put the analog clock in the middle of the screen.
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index 95981427b642..078108d658ee 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -15,6 +15,7 @@
*/
package com.android.keyguard.clock;
+import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
@@ -25,16 +26,18 @@ import android.os.Looper;
import android.provider.Settings;
import android.view.LayoutInflater;
+import androidx.annotation.VisibleForTesting;
+
import com.android.keyguard.R;
+import com.android.systemui.dock.DockManager;
+import com.android.systemui.dock.DockManager.DockEventListener;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.ExtensionController.Extension;
import java.util.ArrayList;
import java.util.List;
-import java.util.Objects;
import java.util.function.Consumer;
-import java.util.function.Supplier;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -45,7 +48,6 @@ import javax.inject.Singleton;
@Singleton
public final class ClockManager {
- private final LayoutInflater mLayoutInflater;
private final ContentResolver mContentResolver;
private final List<ClockInfo> mClockInfos = new ArrayList<>();
@@ -62,7 +64,6 @@ public final class ClockManager {
}
}
};
-
private final ExtensionController mExtensionController;
/**
* Used to select between plugin or default implementations of ClockPlugin interface.
@@ -72,13 +73,35 @@ public final class ClockManager {
* Consumer that accepts the a new ClockPlugin implementation when the Extension reloads.
*/
private final Consumer<ClockPlugin> mClockPluginConsumer = this::setClockPlugin;
+ /**
+ * Supplier of default ClockPlugin implementation.
+ */
+ private final DefaultClockSupplier mDefaultClockSupplier;
+ /**
+ * Observe changes to dock state to know when to switch the clock face.
+ */
+ private final DockEventListener mDockEventListener =
+ new DockEventListener() {
+ @Override
+ public void onEvent(int event) {
+ final boolean isDocked = (event == DockManager.STATE_DOCKED
+ || event == DockManager.STATE_DOCKED_HIDE);
+ mDefaultClockSupplier.setDocked(isDocked);
+ if (mClockExtension != null) {
+ mClockExtension.reload();
+ }
+ }
+ };
+ @Nullable
+ private final DockManager mDockManager;
private final List<ClockChangedListener> mListeners = new ArrayList<>();
@Inject
- public ClockManager(Context context, ExtensionController extensionController) {
+ public ClockManager(Context context, ExtensionController extensionController,
+ @Nullable DockManager dockManager) {
mExtensionController = extensionController;
- mLayoutInflater = LayoutInflater.from(context);
+ mDockManager = dockManager;
mContentResolver = context.getContentResolver();
Resources res = context.getResources();
@@ -110,6 +133,9 @@ public final class ClockManager {
.setThumbnail(() -> BitmapFactory.decodeResource(res, R.drawable.type_thumbnail))
.setPreview(() -> BitmapFactory.decodeResource(res, R.drawable.type_preview))
.build());
+
+ mDefaultClockSupplier = new DefaultClockSupplier(new SettingsWrapper(mContentResolver),
+ LayoutInflater.from(context));
}
/**
@@ -154,41 +180,32 @@ public final class ClockManager {
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE),
false, mContentObserver);
+ mContentResolver.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.DOCKED_CLOCK_FACE),
+ false, mContentObserver);
+ if (mDockManager != null) {
+ mDockManager.addListener(mDockEventListener);
+ }
mClockExtension = mExtensionController.newExtension(ClockPlugin.class)
.withPlugin(ClockPlugin.class)
.withCallback(mClockPluginConsumer)
- // Using withDefault even though this isn't the default as a workaround.
- // ExtensionBuilder doesn't provide the ability to supply a ClockPlugin
- // instance based off of the value of a setting. Since multiple "default"
- // can be provided, using a supplier that changes the settings value.
- // A null return will cause Extension#reload to look at the next "default"
- // supplier.
- .withDefault(
- new SettingsGattedSupplier(
- mContentResolver,
- Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
- BubbleClockController.class.getName(),
- () -> BubbleClockController.build(mLayoutInflater)))
- .withDefault(
- new SettingsGattedSupplier(
- mContentResolver,
- Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
- StretchAnalogClockController.class.getName(),
- () -> StretchAnalogClockController.build(mLayoutInflater)))
- .withDefault(
- new SettingsGattedSupplier(
- mContentResolver,
- Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
- TypeClockController.class.getName(),
- () -> TypeClockController.build(mLayoutInflater)))
+ .withDefault(mDefaultClockSupplier)
.build();
}
private void unregister() {
mContentResolver.unregisterContentObserver(mContentObserver);
+ if (mDockManager != null) {
+ mDockManager.removeListener(mDockEventListener);
+ }
mClockExtension.destroy();
}
+ @VisibleForTesting
+ boolean isDocked() {
+ return mDefaultClockSupplier.isDocked();
+ }
+
/**
* Listener for events that should cause the custom clock face to change.
*/
@@ -200,44 +217,4 @@ public final class ClockManager {
*/
void onClockChanged(ClockPlugin clock);
}
-
- /**
- * Supplier that only gets an instance when a settings value matches expected value.
- */
- private static class SettingsGattedSupplier implements Supplier<ClockPlugin> {
-
- private final ContentResolver mContentResolver;
- private final String mKey;
- private final String mValue;
- private final Supplier<ClockPlugin> mSupplier;
-
- /**
- * Constructs a supplier that changes secure setting key against value.
- *
- * @param contentResolver Used to look up settings value.
- * @param key Settings key.
- * @param value If the setting matches this values that get supplies a ClockPlugin
- * instance.
- * @param supplier Supplier of ClockPlugin instance, only used if the setting
- * matches value.
- */
- SettingsGattedSupplier(ContentResolver contentResolver, String key, String value,
- Supplier<ClockPlugin> supplier) {
- mContentResolver = contentResolver;
- mKey = key;
- mValue = value;
- mSupplier = supplier;
- }
-
- /**
- * Returns null if the settings value doesn't match the expected value.
- *
- * A null return causes Extension#reload to skip this supplier and move to the next.
- */
- @Override
- public ClockPlugin get() {
- final String currentValue = Settings.Secure.getString(mContentResolver, mKey);
- return Objects.equals(currentValue, mValue) ? mSupplier.get() : null;
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/DefaultClockSupplier.java b/packages/SystemUI/src/com/android/keyguard/clock/DefaultClockSupplier.java
new file mode 100644
index 000000000000..7fdd2357bc8e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/DefaultClockSupplier.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import android.util.ArrayMap;
+import android.view.LayoutInflater;
+
+import com.android.systemui.plugins.ClockPlugin;
+
+import java.util.Map;
+import java.util.function.Supplier;
+
+/**
+ * Supplier that only gets an instance when a settings value matches expected value.
+ */
+public class DefaultClockSupplier implements Supplier<ClockPlugin> {
+
+ private final SettingsWrapper mSettingsWrapper;
+ /**
+ * Map from expected value stored in settings to supplier of custom clock face.
+ */
+ private final Map<String, Supplier<ClockPlugin>> mClocks = new ArrayMap<>();
+ /**
+ * When docked, the DOCKED_CLOCK_FACE setting will be checked for the custom clock face
+ * to show.
+ */
+ private boolean mIsDocked;
+
+ /**
+ * Constructs a supplier that changes secure setting key against value.
+ *
+ * @param settingsWrapper Wrapper around settings used to look up the custom clock face.
+ * @param layoutInflater Provided to clocks as dependency to inflate clock views.
+ */
+ public DefaultClockSupplier(SettingsWrapper settingsWrapper, LayoutInflater layoutInflater) {
+ mSettingsWrapper = settingsWrapper;
+
+ mClocks.put(BubbleClockController.class.getName(),
+ () -> BubbleClockController.build(layoutInflater));
+ mClocks.put(StretchAnalogClockController.class.getName(),
+ () -> StretchAnalogClockController.build(layoutInflater));
+ mClocks.put(TypeClockController.class.getName(),
+ () -> TypeClockController.build(layoutInflater));
+ }
+
+ /**
+ * Sets the dock state.
+ *
+ * @param isDocked True when docked, false otherwise.
+ */
+ public void setDocked(boolean isDocked) {
+ mIsDocked = isDocked;
+ }
+
+ boolean isDocked() {
+ return mIsDocked;
+ }
+
+ /**
+ * Get the custom clock face based on values in settings.
+ *
+ * @return Custom clock face, null if the settings value doesn't match a custom clock.
+ */
+ @Override
+ public ClockPlugin get() {
+ ClockPlugin plugin = null;
+ if (mIsDocked) {
+ final String name = mSettingsWrapper.getDockedClockFace();
+ if (name != null) {
+ Supplier<ClockPlugin> supplier = mClocks.get(name);
+ if (supplier != null) {
+ plugin = supplier.get();
+ if (plugin != null) {
+ return plugin;
+ }
+ }
+ }
+ }
+ final String name = mSettingsWrapper.getLockScreenCustomClockFace();
+ if (name != null) {
+ Supplier<ClockPlugin> supplier = mClocks.get(name);
+ if (supplier != null) {
+ plugin = supplier.get();
+ }
+ }
+ return plugin;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java b/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java
index 2c709e0393bd..e35cf113c111 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java
@@ -78,6 +78,16 @@ public class ImageClock extends FrameLayout {
mTime.setTimeZone(timeZone);
}
+ /**
+ * Sets the colors to use on the clock face.
+ * @param dark Darker color obtained from color palette.
+ * @param light Lighter color obtained from color palette.
+ */
+ public void setClockColors(int dark, int light) {
+ mHourHand.setColorFilter(dark);
+ mMinuteHand.setColorFilter(light);
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java b/packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java
new file mode 100644
index 000000000000..58e11553af9d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/SettingsWrapper.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import android.content.ContentResolver;
+import android.provider.Settings;
+
+/**
+ * Wrapper around Settings used for testing.
+ */
+public class SettingsWrapper {
+
+ private static final String CUSTOM_CLOCK_FACE = Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE;
+ private static final String DOCKED_CLOCK_FACE = Settings.Secure.DOCKED_CLOCK_FACE;
+
+ private ContentResolver mContentResolver;
+
+ public SettingsWrapper(ContentResolver contentResolver) {
+ mContentResolver = contentResolver;
+ }
+
+ /**
+ * Gets the value stored in settings for the custom clock face.
+ */
+ public String getLockScreenCustomClockFace() {
+ return Settings.Secure.getString(mContentResolver, CUSTOM_CLOCK_FACE);
+ }
+
+ /**
+ * Gets the value stored in settings for the clock face to use when docked.
+ */
+ public String getDockedClockFace() {
+ return Settings.Secure.getString(mContentResolver, DOCKED_CLOCK_FACE);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java
index 8734754541a6..3c9a4f821c62 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java
@@ -76,10 +76,12 @@ public class StretchAnalogClock extends View {
}
/**
- * Set the color of the minute hand.
+ * Set the colors to use on the clock face.
+ * @param dark Darker color obtained from color palette.
+ * @param light Lighter color obtained from color palette.
*/
- public void setMinuteHandColor(int color) {
- mMinutePaint.setColor(color);
+ public void setClockColor(int dark, int light) {
+ mHourPaint.setColor(dark);
invalidate();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java
index 0a39158cd4be..c4651149521c 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java
@@ -89,8 +89,17 @@ public class StretchAnalogClockController implements ClockPlugin {
@Override
public void setTextColor(int color) {
mLockClock.setTextColor(color);
- mDigitalClock.setTextColor(color);
- mAnalogClock.setMinuteHandColor(color);
+ }
+
+ @Override
+ public void setColorPalette(boolean supportsDarkText, int[] colorPalette) {
+ if (colorPalette == null || colorPalette.length == 0) {
+ return;
+ }
+ final int length = colorPalette.length;
+ mDigitalClock.setTextColor(colorPalette[Math.max(0, length - 5)]);
+ mAnalogClock.setClockColor(colorPalette[Math.max(0, length - 5)],
+ colorPalette[Math.max(0, length - 2)]);
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java
index 17d929dc8a3b..2ea39c40bee2 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java
@@ -87,6 +87,15 @@ public class TypeClockController implements ClockPlugin {
}
@Override
+ public void setColorPalette(boolean supportsDarkText, int[] colorPalette) {
+ if (colorPalette == null || colorPalette.length == 0) {
+ return;
+ }
+ final int length = colorPalette.length;
+ mTypeClock.setClockColor(colorPalette[Math.max(0, length - 5)]);
+ }
+
+ @Override
public void dozeTimeTick() {
mTypeClock.onTimeChanged();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java b/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java
index 8feae53159ac..6f1b59c69865 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java
@@ -43,7 +43,7 @@ public class TypographicClock extends TextView {
private final Resources mResources;
private final String[] mHours;
private final String[] mMinutes;
- private final int mAccentColor;
+ private int mAccentColor;
private Calendar mTime;
private String mDescFormat;
private TimeZone mTimeZone;
@@ -106,6 +106,13 @@ public class TypographicClock extends TextView {
mTime.setTimeZone(timeZone);
}
+ /**
+ * Sets the accent color used on the clock face.
+ */
+ public void setClockColor(int color) {
+ mAccentColor = color;
+ }
+
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
index ce9c637cebf6..3c6f081d0373 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
@@ -21,11 +21,13 @@ import com.android.systemui.appops.AppOpsControllerImpl;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.VolumeDialogController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.power.PowerNotificationWarnings;
import com.android.systemui.power.PowerUI;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
import com.android.systemui.statusbar.phone.ManagedProfileController;
import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
@@ -194,6 +196,12 @@ public abstract class DependencyBinder {
/**
*/
@Binds
+ public abstract StatusBarStateController provideStatusBarStateController(
+ StatusBarStateControllerImpl controllerImpl);
+
+ /**
+ */
+ @Binds
public abstract StatusBarIconController provideStatusBarIconController(
StatusBarIconControllerImpl controllerImpl);
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
index e28aa9d369cb..2a1d066d356e 100644
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
@@ -23,7 +23,6 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
-import android.content.res.Configuration;
import android.provider.Settings;
import android.util.AttributeSet;
import android.view.Gravity;
@@ -59,7 +58,6 @@ public class HardwareUiLayout extends MultiListLayout implements Tunable {
private int mEndPoint;
private boolean mEdgeBleed;
private boolean mRoundedDivider;
- private int mRotation = ROTATION_NONE;
private boolean mRotatedBackground;
private boolean mSwapOrientation = true;
@@ -89,7 +87,7 @@ public class HardwareUiLayout extends MultiListLayout implements Tunable {
}
@Override
- public ViewGroup getParentView(boolean separated, int index) {
+ public ViewGroup getParentView(boolean separated, int index, boolean reverse) {
if (separated) {
return getSeparatedView();
} else {
@@ -174,7 +172,6 @@ public class HardwareUiLayout extends MultiListLayout implements Tunable {
mSeparatedView.setBackground(mSeparatedViewBackground);
updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
mOldHeight = mList.getMeasuredHeight();
- updateRotation();
} else {
return;
}
@@ -188,25 +185,13 @@ public class HardwareUiLayout extends MultiListLayout implements Tunable {
post(() -> updatePosition());
}
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- updateRotation();
- }
-
public void setSwapOrientation(boolean swapOrientation) {
mSwapOrientation = swapOrientation;
}
- private void updateRotation() {
- int rotation = RotationUtils.getRotation(getContext());
- if (rotation != mRotation) {
- rotate(mRotation, rotation);
- mRotation = rotation;
- }
- }
-
- private void rotate(int from, int to) {
+ @Override
+ protected void rotate(int from, int to) {
+ super.rotate(from, to);
if (from != ROTATION_NONE && to != ROTATION_NONE) {
// Rather than handling this confusing case, just do 2 rotations.
rotate(from, ROTATION_NONE);
diff --git a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
index 85265f458370..00ff518ce212 100644
--- a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
@@ -17,11 +17,14 @@
package com.android.systemui;
import android.content.Context;
+import android.content.res.Configuration;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
+import com.android.systemui.util.leak.RotationUtils;
+
/**
* Layout class representing the Global Actions menu which appears when the power button is held.
*/
@@ -32,8 +35,12 @@ public abstract class MultiListLayout extends LinearLayout {
protected int mExpectedSeparatedItemCount;
protected int mExpectedListItemCount;
+ protected int mRotation;
+ protected RotationListener mRotationListener;
+
public MultiListLayout(Context context, AttributeSet attrs) {
super(context, attrs);
+ mRotation = RotationUtils.getRotation(context);
}
protected abstract ViewGroup getSeparatedView();
@@ -50,10 +57,12 @@ public abstract class MultiListLayout extends LinearLayout {
* @param separated Whether or not this index refers to a position in the separated or list
* container.
* @param index The index of the item within the container.
+ * @param reverse If the MultiListLayout contains sub-lists within the list container, reverse
+ * the order that they are filled.
* @return The parent ViewGroup which will be used to contain the specified item
* after it has been added to the layout.
*/
- public abstract ViewGroup getParentView(boolean separated, int index);
+ public abstract ViewGroup getParentView(boolean separated, int index, boolean reverse);
/**
* Sets the divided view, which may have a differently-colored background.
@@ -111,6 +120,26 @@ public abstract class MultiListLayout extends LinearLayout {
setFocusable(true);
}
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ int newRotation = RotationUtils.getRotation(mContext);
+ if (newRotation != mRotation) {
+ rotate(mRotation, newRotation);
+ mRotation = newRotation;
+ }
+ }
+
+ protected void rotate(int from, int to) {
+ if (mRotationListener != null) {
+ mRotationListener.onRotate(from, to);
+ }
+ }
+
+ public void setRotationListener(RotationListener listener) {
+ mRotationListener = listener;
+ }
+
/**
* Retrieve the MultiListLayout associated with the given view.
*/
@@ -121,4 +150,8 @@ public abstract class MultiListLayout extends LinearLayout {
}
return null;
}
+
+ interface RotationListener {
+ void onRotate(int from, int to);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 755d6fcffb43..6d583df6082b 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -31,6 +31,7 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.dock.DockManager;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -41,7 +42,6 @@ import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
import com.android.systemui.statusbar.ScrimView;
-import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotificationData;
@@ -153,15 +153,6 @@ public class SystemUIFactory {
return new VolumeDialogComponent(systemUi, context);
}
- /**
- * Provides status bar state controller implementation
- */
- @Singleton
- @Provides
- public StatusBarStateController provideStatusBarStateController(Context context) {
- return new StatusBarStateControllerImpl();
- }
-
@Singleton
@Provides
public NotificationData.KeyguardEnvironment provideKeyguardEnvironment(Context context) {
@@ -228,6 +219,16 @@ public class SystemUIFactory {
return SysUiServiceProvider.getComponent(context, StatusBar.class);
}
+ /**
+ * Provides DockManager.
+ */
+ @Singleton
+ @Provides
+ @Nullable
+ public DockManager providesDockManager(Context context) {
+ return SysUiServiceProvider.getComponent(context, DockManager.class);
+ }
+
@Module
protected static class ContextHolder {
private Context mContext;
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 4d708908975e..038f4912e40f 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -290,10 +290,6 @@ public class AssistManager implements ConfigurationChangedReceiver {
return mAssistUtils.isSessionRunning();
}
- public void destroy() {
- mWindowManager.removeViewImmediate(mView);
- }
-
private void maybeSwapSearchIcon(@NonNull ComponentName assistComponent, boolean isService) {
replaceDrawable(mView.getOrb().getLogo(), assistComponent, ASSIST_ICON_METADATA_NAME,
isService);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
new file mode 100644
index 000000000000..4778434e2052
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.bubbles;
+
+
+import android.view.LayoutInflater;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+/**
+ * Encapsulates the data and UI elements of a bubble.
+ */
+class Bubble {
+
+ public BubbleView iconView;
+ public BubbleExpandedView expandedView;
+ public String key;
+ public NotificationEntry entry;
+
+ Bubble(NotificationEntry e, LayoutInflater inflater, BubbleStackView stackView,
+ BubbleExpandedView.OnBubbleBlockedListener listener) {
+ entry = e;
+ key = entry.key;
+
+ iconView = (BubbleView) inflater.inflate(
+ R.layout.bubble_view, stackView, false /* attachToRoot */);
+ iconView.setNotif(entry);
+
+ expandedView = (BubbleExpandedView) inflater.inflate(
+ R.layout.bubble_expanded_view, stackView, false /* attachToRoot */);
+ expandedView.setEntry(entry, stackView);
+
+ expandedView.setOnBlockedListener(listener);
+ }
+
+ public void setEntry(NotificationEntry entry) {
+ key = entry.key;
+ iconView.update(entry);
+ // TODO: should also update the expanded view here (e.g. height change)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 41bc1b29075c..be2dd679bba5 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -16,10 +16,6 @@
package com.android.systemui.bubbles;
-import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
-import static android.util.StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING;
-import static android.util.StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE;
-import static android.util.StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
@@ -33,21 +29,14 @@ import android.app.ActivityTaskManager;
import android.app.IActivityTaskManager;
import android.app.INotificationManager;
import android.app.Notification;
-import android.app.PendingIntent;
import android.content.Context;
-import android.content.pm.ActivityInfo;
-import android.graphics.Point;
import android.graphics.Rect;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
-import android.util.Log;
-import android.util.StatsLog;
import android.view.Display;
-import android.view.LayoutInflater;
import android.view.ViewGroup;
-import android.view.WindowManager;
import android.widget.FrameLayout;
import androidx.annotation.MainThread;
@@ -66,10 +55,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationInflater;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -105,11 +91,9 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe
private final BubbleTaskStackListener mTaskStackListener;
private BubbleStateChangeListener mStateChangeListener;
private BubbleExpandListener mExpandListener;
- private LayoutInflater mInflater;
- private final Map<String, BubbleView> mBubbles = new HashMap<>();
+ private BubbleData mBubbleData;
private BubbleStackView mStackView;
- private final Point mDisplaySize;
// Bubbles get added to the status bar view
private final StatusBarWindowController mStatusBarWindowController;
@@ -166,12 +150,9 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe
}
@Inject
- public BubbleController(Context context, StatusBarWindowController statusBarWindowController) {
+ public BubbleController(Context context, StatusBarWindowController statusBarWindowController,
+ BubbleData data) {
mContext = context;
- WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- mDisplaySize = new Point();
- wm.getDefaultDisplay().getSize(mDisplaySize);
- mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
mNotificationEntryManager.addNotificationEntryListener(mEntryListener);
@@ -190,6 +171,8 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe
mActivityTaskManager = ActivityTaskManager.getService();
mTaskStackListener = new BubbleTaskStackListener();
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
+
+ mBubbleData = data;
}
/**
@@ -219,8 +202,11 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe
* screen (e.g. if on AOD).
*/
public boolean hasBubbles() {
- for (BubbleView bv : mBubbles.values()) {
- if (!bv.getEntry().isBubbleDismissed()) {
+ if (mStackView == null) {
+ return false;
+ }
+ for (Bubble bubble : mBubbleData.getBubbles()) {
+ if (!bubble.entry.isBubbleDismissed()) {
return true;
}
}
@@ -250,10 +236,6 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe
if (mStackView == null) {
return;
}
- Set<String> keys = mBubbles.keySet();
- for (String key: keys) {
- mBubbles.get(key).getEntry().setBubbleDismissed(true);
- }
mStackView.stackDismissed();
updateVisibility();
@@ -267,13 +249,12 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe
* @param updatePosition whether this update should promote the bubble to the top of the stack.
*/
public void updateBubble(NotificationEntry notif, boolean updatePosition) {
- if (mBubbles.containsKey(notif.key)) {
+ if (mStackView != null && mBubbleData.getBubble(notif.key) != null) {
// It's an update
- BubbleView bubble = mBubbles.get(notif.key);
- mStackView.updateBubble(bubble, notif, updatePosition);
+ mStackView.updateBubble(notif, updatePosition);
} else {
if (mStackView == null) {
- mStackView = new BubbleStackView(mContext);
+ mStackView = new BubbleStackView(mContext, mBubbleData);
ViewGroup sbv = mStatusBarWindowController.getStatusBarView();
// XXX: Bug when you expand the shade on top of expanded bubble, there is no scrim
// between bubble and the shade
@@ -286,15 +267,7 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe
mStackView.setOnBlockedListener(this);
}
// It's new
- BubbleView bubble = (BubbleView) mInflater.inflate(
- R.layout.bubble_view, mStackView, false /* attachToRoot */);
- bubble.setNotif(notif);
- PendingIntent bubbleIntent = getValidBubbleIntent(notif);
- if (bubbleIntent != null) {
- bubble.setBubbleIntent(bubbleIntent);
- }
- mBubbles.put(bubble.getKey(), bubble);
- mStackView.addBubble(bubble);
+ mStackView.addBubble(notif);
}
updateVisibility();
}
@@ -306,25 +279,18 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe
*/
@MainThread
void removeBubble(String key) {
- BubbleView bv = mBubbles.remove(key);
- if (mStackView != null && bv != null) {
- mStackView.removeBubble(bv);
- bv.destroyActivityView(mStackView);
- }
-
- NotificationEntry entry = bv != null ? bv.getEntry() : null;
- if (entry != null) {
- entry.setBubbleDismissed(true);
- mNotificationEntryManager.updateNotifications();
+ if (mStackView != null) {
+ mStackView.removeBubble(key);
}
+ mNotificationEntryManager.updateNotifications();
updateVisibility();
}
@Override
public void onBubbleBlocked(NotificationEntry entry) {
- Object[] bubbles = mBubbles.values().toArray();
+ Object[] bubbles = mBubbleData.getBubbles().toArray();
for (int i = 0; i < bubbles.length; i++) {
- NotificationEntry e = ((BubbleView) bubbles[i]).getEntry();
+ NotificationEntry e = ((Bubble) bubbles[i]).entry;
boolean samePackage = entry.notification.getPackageName().equals(
e.notification.getPackageName());
if (samePackage) {
@@ -368,10 +334,8 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe
&& alertAgain(entry, entry.notification.getNotification())) {
entry.setShowInShadeWhenBubble(true);
entry.setBubbleDismissed(false); // updates come back as bubbles even if dismissed
- if (mBubbles.containsKey(entry.key)) {
- mBubbles.get(entry.key).updateDotVisibility();
- }
updateBubble(entry, true /* updatePosition */);
+ mStackView.updateDotVisibility(entry.key);
}
}
@@ -383,8 +347,8 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe
return;
}
entry.setShowInShadeWhenBubble(false);
- if (mBubbles.containsKey(entry.key)) {
- mBubbles.get(entry.key).updateDotVisibility();
+ if (mStackView != null) {
+ mStackView.updateDotVisibility(entry.key);
}
if (!removedByUser) {
// This was a cancel so we should remove the bubble
@@ -441,65 +405,6 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe
return mStackView;
}
- @Nullable
- private PendingIntent getValidBubbleIntent(NotificationEntry notif) {
- Notification notification = notif.notification.getNotification();
- String packageName = notif.notification.getPackageName();
- Notification.BubbleMetadata data = notif.getBubbleMetadata();
- if (data != null && canLaunchInActivityView(data.getIntent(),
- true /* enable logging for bubbles */, packageName)) {
- return data.getIntent();
- }
- if (shouldUseContentIntent(mContext)
- && canLaunchInActivityView(notification.contentIntent,
- false /* disable logging for notifications */, packageName)) {
- Log.d(TAG, "[addBubble " + notif.key
- + "]: No appOverlayIntent, using contentIntent.");
- return notification.contentIntent;
- }
- Log.d(TAG, "[addBubble " + notif.key + "]: No supported intent for ActivityView.");
- return null;
- }
-
- /**
- * Whether an intent is properly configured to display in an {@link android.app.ActivityView}.
- *
- * @param intent the pending intent of the bubble.
- * @param enableLogging whether bubble developer error should be logged.
- * @param packageName the notification package name for this bubble.
- * @return
- */
- private boolean canLaunchInActivityView(PendingIntent intent, boolean enableLogging,
- String packageName) {
- if (intent == null) {
- return false;
- }
- ActivityInfo info =
- intent.getIntent().resolveActivityInfo(mContext.getPackageManager(), 0);
- if (info == null) {
- if (enableLogging) {
- StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
- BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING);
- }
- return false;
- }
- if (!ActivityInfo.isResizeableMode(info.resizeMode)) {
- if (enableLogging) {
- StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
- BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE);
- }
- return false;
- }
- if (info.documentLaunchMode != DOCUMENT_LAUNCH_ALWAYS) {
- if (enableLogging) {
- StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
- BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS);
- }
- return false;
- }
- return (info.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) != 0;
- }
-
/**
* Whether the notification has been developer configured to bubble and is allowed by the user.
*/
@@ -620,7 +525,7 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe
ENABLE_AUTO_BUBBLE_ALL, 0) != 0;
}
- private static boolean shouldUseContentIntent(Context context) {
+ static boolean shouldUseContentIntent(Context context) {
return Settings.Secure.getInt(context.getContentResolver(),
ENABLE_BUBBLE_CONTENT_INTENT, 0) != 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
new file mode 100644
index 000000000000..5002f5cce751
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.bubbles;
+
+import androidx.annotation.Nullable;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+import java.util.Collection;
+import java.util.HashMap;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Keeps track of active bubbles.
+ */
+@Singleton
+class BubbleData {
+
+ private HashMap<String, Bubble> mBubbles = new HashMap<>();
+
+ @Inject
+ BubbleData() {}
+
+ /**
+ * The set of bubbles.
+ */
+ public Collection<Bubble> getBubbles() {
+ return mBubbles.values();
+ }
+
+ @Nullable
+ public Bubble getBubble(String key) {
+ return mBubbles.get(key);
+ }
+
+ public void addBubble(Bubble b) {
+ mBubbles.put(b.key, b);
+ }
+
+ @Nullable
+ public Bubble removeBubble(String key) {
+ return mBubbles.remove(key);
+ }
+
+ public void updateBubble(String key, NotificationEntry newEntry) {
+ Bubble oldBubble = mBubbles.get(key);
+ if (oldBubble != null) {
+ oldBubble.setEntry(newEntry);
+ }
+ }
+
+ public void clear() {
+ mBubbles.clear();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index bf9d7ba61189..492eadd240ed 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -16,37 +16,53 @@
package com.android.systemui.bubbles;
+import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
+import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING;
+import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE;
+import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS;
+
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.annotation.Nullable;
+import android.app.ActivityView;
import android.app.INotificationManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
+import android.graphics.Insets;
+import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.StatsLog;
import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.TriangleShape;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
/**
* Container for the expanded bubble view, handles rendering the caret and header of the view.
@@ -66,8 +82,15 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
// Permission view
private View mPermissionView;
- // The view that is being displayed for the expanded state
- private View mExpandedView;
+ // Views for expanded state
+ private ExpandableNotificationRow mNotifRow;
+ private ActivityView mActivityView;
+
+ private boolean mActivityViewReady = false;
+ private PendingIntent mBubbleIntent;
+
+ private int mBubbleHeight;
+ private int mDefaultHeight;
private NotificationEntry mEntry;
private PackageManager mPm;
@@ -75,11 +98,40 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
private Drawable mAppIcon;
private INotificationManager mNotificationManagerService;
+ private BubbleController mBubbleController = Dependency.get(BubbleController.class);
- // Need reference to let it know to collapse when new task is launched
private BubbleStackView mStackView;
- private OnBubbleBlockedListener mOnBubbleBlockedListener;
+ private BubbleExpandedView.OnBubbleBlockedListener mOnBubbleBlockedListener;
+
+ private ActivityView.StateCallback mStateCallback = new ActivityView.StateCallback() {
+ @Override
+ public void onActivityViewReady(ActivityView view) {
+ if (!mActivityViewReady) {
+ mActivityViewReady = true;
+ mActivityView.startActivity(mBubbleIntent);
+ }
+ }
+
+ @Override
+ public void onActivityViewDestroyed(ActivityView view) {
+ mActivityViewReady = false;
+ }
+
+ /**
+ * This is only called for tasks on this ActivityView, which is also set to
+ * single-task mode -- meaning never more than one task on this display. If a task
+ * is being removed, it's the top Activity finishing and this bubble should
+ * be removed or collapsed.
+ */
+ @Override
+ public void onTaskRemovalStarted(int taskId) {
+ if (mEntry != null) {
+ // Must post because this is called from a binder thread.
+ post(() -> mBubbleController.removeBubble(mEntry.key));
+ }
+ }
+ };
public BubbleExpandedView(Context context) {
this(context, null);
@@ -97,6 +149,8 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mPm = context.getPackageManager();
+ mDefaultHeight = getResources().getDimensionPixelSize(
+ R.dimen.bubble_expanded_default_height);
try {
mNotificationManagerService = INotificationManager.Stub.asInterface(
ServiceManager.getServiceOrThrow(Context.NOTIFICATION_SERVICE));
@@ -150,6 +204,28 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
mPermissionView = findViewById(R.id.permission_layout);
findViewById(R.id.no_bubbles_button).setOnClickListener(this);
findViewById(R.id.yes_bubbles_button).setOnClickListener(this);
+
+ mActivityView = new ActivityView(mContext, null /* attrs */, 0 /* defStyle */,
+ true /* singleTaskInstance */);
+ addView(mActivityView);
+
+ mActivityView.setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
+ ActivityView activityView = (ActivityView) view;
+ // Here we assume that the position of the ActivityView on the screen
+ // remains regardless of IME status. When we move ActivityView, the
+ // forwardedInsets should be computed not against the current location
+ // and size, but against the post-moved location and size.
+ Point displaySize = new Point();
+ view.getContext().getDisplay().getSize(displaySize);
+ int[] windowLocation = view.getLocationOnScreen();
+ final int windowBottom = windowLocation[1] + view.getHeight();
+ final int keyboardHeight = insets.getSystemWindowInsetBottom()
+ - insets.getStableInsetBottom();
+ final int insetsBottom = Math.max(0,
+ windowBottom + keyboardHeight - displaySize.y);
+ activityView.setForwardedInsets(Insets.of(0, 0, 0, insetsBottom));
+ return view.onApplyWindowInsets(insets);
+ });
}
/**
@@ -187,6 +263,14 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
}
updateHeaderView();
updatePermissionView();
+ updateExpandedView();
+ }
+
+ /**
+ * Lets activity view know it should be shown / populated.
+ */
+ public void populateActivityView() {
+ mActivityView.setCallback(mStateCallback);
}
private void updateHeaderView() {
@@ -223,6 +307,34 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
}
}
+ private void updateExpandedView() {
+ mBubbleIntent = getBubbleIntent(mEntry);
+ if (mBubbleIntent != null) {
+ if (mNotifRow != null) {
+ // Clear out the row if we had it previously
+ removeView(mNotifRow);
+ mNotifRow = null;
+ }
+ Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
+ mBubbleHeight = data != null && data.getDesiredHeight() > 0
+ ? data.getDesiredHeight()
+ : mDefaultHeight;
+ // XXX: enforce max / min height
+ LayoutParams lp = (LayoutParams) mActivityView.getLayoutParams();
+ lp.height = mBubbleHeight;
+ mActivityView.setLayoutParams(lp);
+ mActivityView.setVisibility(VISIBLE);
+ } else {
+ // Hide activity view if we had it previously
+ mActivityView.setVisibility(GONE);
+
+ // Use notification view
+ mNotifRow = mEntry.getRow();
+ addView(mNotifRow);
+ }
+ updateView();
+ }
+
@Override
public void onClick(View view) {
if (mEntry == null) {
@@ -234,6 +346,8 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
mStackView.collapseStack(() -> {
try {
n.contentIntent.send();
+ logBubbleClickEvent(mEntry.notification,
+ StatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_APP);
} catch (PendingIntent.CanceledException e) {
Log.w(TAG, "Failed to send intent for bubble with key: "
+ (mEntry != null ? mEntry.key : " null entry"));
@@ -242,7 +356,11 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
} else if (id == R.id.settings_button) {
Intent intent = getSettingsIntent(mEntry.notification.getPackageName(),
mEntry.notification.getUid());
- mStackView.collapseStack(() -> mContext.startActivity(intent));
+ mStackView.collapseStack(() -> {
+ mContext.startActivity(intent);
+ logBubbleClickEvent(mEntry.notification,
+ StatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS);
+ });
} else if (id == R.id.no_bubbles_button) {
setBubblesAllowed(false);
} else if (id == R.id.yes_bubbles_button) {
@@ -262,42 +380,96 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
} else if (mOnBubbleBlockedListener != null) {
mOnBubbleBlockedListener.onBubbleBlocked(mEntry);
}
+ logBubbleClickEvent(mEntry.notification,
+ allowed ? StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_OPT_IN :
+ StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_OPT_OUT);
} catch (RemoteException e) {
Log.w(TAG, e);
}
}
/**
+ * Update appearance of the expanded view being displayed.
+ */
+ public void updateView() {
+ if (usingActivityView()
+ && mActivityView.getVisibility() == VISIBLE
+ && mActivityView.isAttachedToWindow()) {
+ mActivityView.onLocationChanged();
+ } else if (mNotifRow != null) {
+ applyRowState(mNotifRow);
+ }
+ }
+
+ /**
* Set the x position that the tip of the triangle should point to.
*/
- public void setPointerPosition(int x) {
+ public void setPointerPosition(float x) {
// Adjust for the pointer size
- x -= (mPointerView.getWidth() / 2);
+ x -= (mPointerView.getWidth() / 2f);
mPointerView.setTranslationX(x);
}
/**
- * Set the view to display for the expanded state. Passing null will clear the view.
+ * Removes and releases an ActivityView if one was previously created for this bubble.
*/
- public void setExpandedView(View view) {
- if (mExpandedView == view) {
+ public void destroyActivityView(ViewGroup tmpParent) {
+ if (mActivityView == null) {
return;
}
- if (mExpandedView != null) {
- removeView(mExpandedView);
+ if (!mActivityViewReady) {
+ // release not needed, never initialized?
+ mActivityView = null;
+ return;
}
- mExpandedView = view;
- if (mExpandedView != null) {
- addView(mExpandedView);
+ // HACK: release() will crash if the view is not attached.
+ if (!isAttachedToWindow()) {
+ mActivityView.setVisibility(View.GONE);
+ tmpParent.addView(this);
}
+
+ mActivityView.release();
+ ((ViewGroup) getParent()).removeView(this);
+ mActivityView = null;
+ mActivityViewReady = false;
}
- /**
- * @return the view containing the expanded content, can be null.
- */
- @Nullable
- public View getExpandedView() {
- return mExpandedView;
+ private boolean usingActivityView() {
+ return mBubbleIntent != null;
+ }
+
+ private void applyRowState(ExpandableNotificationRow view) {
+ view.reset();
+ view.setHeadsUp(false);
+ view.resetTranslation();
+ view.setOnKeyguard(false);
+ view.setOnAmbient(false);
+ view.setClipBottomAmount(0);
+ view.setClipTopAmount(0);
+ view.setContentTransformationAmount(0, false);
+ view.setIconsVisible(true);
+
+ // TODO - Need to reset this (and others) when view goes back in shade, leave for now
+ // view.setTopRoundness(1, false);
+ // view.setBottomRoundness(1, false);
+
+ ExpandableViewState viewState = view.getViewState();
+ viewState = viewState == null ? new ExpandableViewState() : viewState;
+ viewState.height = view.getIntrinsicHeight();
+ viewState.gone = false;
+ viewState.hidden = false;
+ viewState.dimmed = false;
+ viewState.dark = false;
+ viewState.alpha = 1f;
+ viewState.notGoneIndex = -1;
+ viewState.xTranslation = 0;
+ viewState.yTranslation = 0;
+ viewState.zTranslation = 0;
+ viewState.scaleX = 1;
+ viewState.scaleY = 1;
+ viewState.inShelf = true;
+ viewState.headsUpIsVisible = false;
+ viewState.applyToView(view);
}
private Intent getSettingsIntent(String packageName, final int appUid) {
@@ -309,6 +481,61 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
return intent;
}
+ @Nullable
+ private PendingIntent getBubbleIntent(NotificationEntry entry) {
+ Notification notif = entry.notification.getNotification();
+ String packageName = entry.notification.getPackageName();
+ Notification.BubbleMetadata data = notif.getBubbleMetadata();
+ if (data != null && canLaunchInActivityView(data.getIntent(), true /* enableLogging */,
+ packageName)) {
+ return data.getIntent();
+ } else if (BubbleController.shouldUseContentIntent(mContext)
+ && canLaunchInActivityView(notif.contentIntent, false /* enableLogging */,
+ packageName)) {
+ return notif.contentIntent;
+ }
+ return null;
+ }
+
+ /**
+ * Whether an intent is properly configured to display in an {@link android.app.ActivityView}.
+ *
+ * @param intent the pending intent of the bubble.
+ * @param enableLogging whether bubble developer error should be logged.
+ * @param packageName the notification package name for this bubble.
+ * @return
+ */
+ private boolean canLaunchInActivityView(PendingIntent intent, boolean enableLogging,
+ String packageName) {
+ if (intent == null) {
+ return false;
+ }
+ ActivityInfo info =
+ intent.getIntent().resolveActivityInfo(mContext.getPackageManager(), 0);
+ if (info == null) {
+ if (enableLogging) {
+ StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
+ BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING);
+ }
+ return false;
+ }
+ if (!ActivityInfo.isResizeableMode(info.resizeMode)) {
+ if (enableLogging) {
+ StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
+ BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE);
+ }
+ return false;
+ }
+ if (info.documentLaunchMode != DOCUMENT_LAUNCH_ALWAYS) {
+ if (enableLogging) {
+ StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
+ BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS);
+ }
+ return false;
+ }
+ return (info.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) != 0;
+ }
+
/**
* Listener that is notified when a bubble is blocked.
*/
@@ -318,4 +545,22 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
*/
void onBubbleBlocked(NotificationEntry entry);
}
+
+ /**
+ * Logs bubble UI click event.
+ *
+ * @param notification the bubble notification that user is interacting with.
+ * @param action the user interaction enum.
+ */
+ private void logBubbleClickEvent(StatusBarNotification notification, int action) {
+ StatsLog.write(StatsLog.BUBBLE_UI_CHANGED,
+ notification.getPackageName(),
+ notification.getNotification().getChannelId(),
+ notification.getId(),
+ mStackView.getBubbleIndex(mStackView.getExpandedBubble()),
+ mStackView.getBubbleCount(),
+ action,
+ mStackView.getNormalizedXPosition(),
+ mStackView.getNormalizedYPosition());
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index f6f3fa646232..62cc8895ac73 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -19,7 +19,6 @@ package com.android.systemui.bubbles;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import android.app.ActivityView;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Outline;
@@ -33,13 +32,11 @@ import android.util.StatsLog;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.widget.FrameLayout;
-import android.widget.LinearLayout;
import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
@@ -54,8 +51,6 @@ import com.android.systemui.bubbles.animation.ExpandedAnimationController;
import com.android.systemui.bubbles.animation.PhysicsAnimationLayout;
import com.android.systemui.bubbles.animation.StackAnimationController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import java.math.BigDecimal;
import java.math.RoundingMode;
@@ -90,27 +85,33 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
private final SpringAnimation mExpandedViewXAnim;
private final SpringAnimation mExpandedViewYAnim;
+ private final BubbleData mBubbleData;
private PhysicsAnimationLayout mBubbleContainer;
private StackAnimationController mStackAnimationController;
private ExpandedAnimationController mExpandedAnimationController;
- private BubbleExpandedView mExpandedViewContainer;
+ private FrameLayout mExpandedViewContainer;
+
private int mBubbleSize;
private int mBubblePadding;
private int mExpandedAnimateXDistance;
private int mExpandedAnimateYDistance;
+ private int mStatusBarHeight;
+ private Bubble mExpandedBubble;
private boolean mIsExpanded;
- private int mExpandedBubbleHeight;
+
private BubbleTouchHandler mTouchHandler;
- private BubbleView mExpandedBubble;
private BubbleController.BubbleExpandListener mExpandListener;
+ private BubbleExpandedView.OnBubbleBlockedListener mBlockedListener;
private boolean mViewUpdatedRequested = false;
private boolean mIsAnimating = false;
+ private LayoutInflater mInflater;
+
// Used for determining view / touch intersection
int[] mTempLoc = new int[2];
RectF mTempRect = new RectF();
@@ -140,9 +141,11 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
}
};
- public BubbleStackView(Context context) {
+ public BubbleStackView(Context context, BubbleData data) {
super(context);
+ mBubbleData = data;
+ mInflater = LayoutInflater.from(context);
mTouchHandler = new BubbleTouchHandler(context);
setOnTouchListener(mTouchHandler);
@@ -153,8 +156,9 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
res.getDimensionPixelSize(R.dimen.bubble_expanded_animate_x_distance);
mExpandedAnimateYDistance =
res.getDimensionPixelSize(R.dimen.bubble_expanded_animate_y_distance);
+ mStatusBarHeight =
+ res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
- mExpandedBubbleHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height);
mDisplaySize = new Point();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getSize(mDisplaySize);
@@ -174,9 +178,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
mBubbleContainer.setClipChildren(false);
addView(mBubbleContainer, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
- mExpandedViewContainer = (BubbleExpandedView)
- LayoutInflater.from(context).inflate(R.layout.bubble_expanded_view,
- this /* parent */, false /* attachToRoot */);
+ mExpandedViewContainer = new FrameLayout(context);
mExpandedViewContainer.setElevation(elevation);
mExpandedViewContainer.setPadding(padding, padding, padding, padding);
mExpandedViewContainer.setClipChildren(false);
@@ -218,6 +220,17 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
}
/**
+ * Updates the visibility of the 'dot' indicating an update on the bubble.
+ * @param key the {@link NotificationEntry#key} associated with the bubble.
+ */
+ public void updateDotVisibility(String key) {
+ Bubble b = mBubbleData.getBubble(key);
+ if (b != null) {
+ b.iconView.updateDotVisibility();
+ }
+ }
+
+ /**
* Sets the listener to notify when the bubble stack is expanded.
*/
public void setExpandListener(BubbleController.BubbleExpandListener listener) {
@@ -228,7 +241,10 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
* Sets the listener to notify when a bubble is blocked.
*/
public void setOnBlockedListener(BubbleExpandedView.OnBubbleBlockedListener listener) {
- mExpandedViewContainer.setOnBlockedListener(listener);
+ mBlockedListener = listener;
+ for (Bubble b : mBubbleData.getBubbles()) {
+ b.expandedView.setOnBlockedListener(mBlockedListener);
+ }
}
/**
@@ -241,19 +257,29 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
/**
* The {@link BubbleView} that is expanded, null if one does not exist.
*/
- public BubbleView getExpandedBubble() {
+ BubbleView getExpandedBubbleView() {
+ return mExpandedBubble != null ? mExpandedBubble.iconView : null;
+ }
+
+ /**
+ * The {@link Bubble} that is expanded, null if one does not exist.
+ */
+ Bubble getExpandedBubble() {
return mExpandedBubble;
}
/**
* Sets the bubble that should be expanded and expands if needed.
+ *
+ * @param key the {@link NotificationEntry#key} associated with the bubble to expand.
*/
- public void setExpandedBubble(BubbleView bubbleToExpand) {
+ void setExpandedBubble(String key) {
+ Bubble bubbleToExpand = mBubbleData.getBubble(key);
if (mIsExpanded && !bubbleToExpand.equals(mExpandedBubble)) {
// Previously expanded, notify that this bubble is no longer expanded
- notifyExpansionChanged(mExpandedBubble, false /* expanded */);
+ notifyExpansionChanged(mExpandedBubble.entry, false /* expanded */);
}
- BubbleView prevBubble = mExpandedBubble;
+ Bubble prevBubble = mExpandedBubble;
mExpandedBubble = bubbleToExpand;
if (!mIsExpanded) {
// If we weren't previously expanded we should animate open.
@@ -268,8 +294,8 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
logBubbleEvent(prevBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
}
- mExpandedBubble.getEntry().setShowInShadeWhenBubble(false);
- notifyExpansionChanged(mExpandedBubble, true /* expanded */);
+ mExpandedBubble.entry.setShowInShadeWhenBubble(false);
+ notifyExpansionChanged(mExpandedBubble.entry, true /* expanded */);
}
/**
@@ -280,7 +306,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
for (int i = 0; i < mBubbleContainer.getChildCount(); i++) {
BubbleView bv = (BubbleView) mBubbleContainer.getChildAt(i);
if (entry.equals(bv.getEntry())) {
- setExpandedBubble(bv);
+ setExpandedBubble(entry.key);
}
}
}
@@ -288,48 +314,67 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
/**
* Adds a bubble to the top of the stack.
*
- * @param bubbleView the view to add to the stack.
+ * @param entry the notification to add to the stack of bubbles.
*/
- public void addBubble(BubbleView bubbleView) {
- mBubbleContainer.addView(bubbleView, 0,
+ public void addBubble(NotificationEntry entry) {
+ Bubble b = new Bubble(entry, mInflater, this /* stackView */, mBlockedListener);
+ mBubbleData.addBubble(b);
+
+ mBubbleContainer.addView(b.iconView, 0,
new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
- ViewClippingUtil.setClippingDeactivated(bubbleView, true, mClippingParameters);
+ ViewClippingUtil.setClippingDeactivated(b.iconView, true, mClippingParameters);
+
requestUpdate();
- logBubbleEvent(bubbleView, StatsLog.BUBBLE_UICHANGED__ACTION__POSTED);
+ logBubbleEvent(b, StatsLog.BUBBLE_UICHANGED__ACTION__POSTED);
}
/**
* Remove a bubble from the stack.
*/
- public void removeBubble(BubbleView bubbleView) {
- int removedIndex = mBubbleContainer.indexOfChild(bubbleView);
- mBubbleContainer.removeView(bubbleView);
+ public void removeBubble(String key) {
+ Bubble b = mBubbleData.removeBubble(key);
+ if (b == null) {
+ return;
+ }
+ b.entry.setBubbleDismissed(true);
+
+ // Remove it from the views
+ int removedIndex = mBubbleContainer.indexOfChild(b.iconView);
+ b.expandedView.destroyActivityView(this /* tmpParent */);
+ mBubbleContainer.removeView(b.iconView);
+
int bubbleCount = mBubbleContainer.getChildCount();
if (bubbleCount == 0) {
// If no bubbles remain, collapse the entire stack.
collapseStack();
return;
- } else if (bubbleView.equals(mExpandedBubble)) {
+ } else if (b.equals(mExpandedBubble)) {
// Was the current bubble just removed?
// If we have other bubbles and are expanded go to the next one or previous
// if the bubble removed was last
int nextIndex = bubbleCount > removedIndex ? removedIndex : bubbleCount - 1;
BubbleView expandedBubble = (BubbleView) mBubbleContainer.getChildAt(nextIndex);
if (mIsExpanded) {
- setExpandedBubble(expandedBubble);
+ setExpandedBubble(expandedBubble.getKey());
} else {
mExpandedBubble = null;
}
}
- logBubbleEvent(bubbleView, StatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED);
+ logBubbleEvent(b, StatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED);
}
/**
* Dismiss the stack of bubbles.
*/
public void stackDismissed() {
+ for (Bubble bubble : mBubbleData.getBubbles()) {
+ bubble.entry.setBubbleDismissed(true);
+ bubble.expandedView.destroyActivityView(this /* tmpParent */);
+ }
+ mBubbleData.clear();
collapseStack();
mBubbleContainer.removeAllViews();
+ mExpandedViewContainer.removeAllViews();
logBubbleEvent(null /* no bubble associated with bubble stack dismiss */,
StatsLog.BUBBLE_UICHANGED__ACTION__STACK_DISMISSED);
}
@@ -337,25 +382,26 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
/**
* Updates a bubble in the stack.
*
- * @param bubbleView the view to update in the stack.
- * @param entry the entry to update it with.
+ * @param entry the entry to update in the stack.
* @param updatePosition whether this bubble should be moved to top of the stack.
*/
- public void updateBubble(BubbleView bubbleView, NotificationEntry entry,
- boolean updatePosition) {
- bubbleView.update(entry);
+ public void updateBubble(NotificationEntry entry, boolean updatePosition) {
+ Bubble b = mBubbleData.getBubble(entry.key);
+ b.iconView.update(entry);
+ // TODO: should also update the expanded view here (e.g. height change)
+
if (updatePosition && !mIsExpanded) {
// If alerting it gets promoted to top of the stack.
- if (mBubbleContainer.indexOfChild(bubbleView) != 0) {
- mBubbleContainer.moveViewTo(bubbleView, 0);
+ if (mBubbleContainer.indexOfChild(b.iconView) != 0) {
+ mBubbleContainer.moveViewTo(b.iconView, 0);
}
requestUpdate();
}
- if (mIsExpanded && bubbleView.equals(mExpandedBubble)) {
+ if (mIsExpanded && entry.equals(mExpandedBubble.entry)) {
entry.setShowInShadeWhenBubble(false);
requestUpdate();
}
- logBubbleEvent(bubbleView, StatsLog.BUBBLE_UICHANGED__ACTION__UPDATED);
+ logBubbleEvent(b, StatsLog.BUBBLE_UICHANGED__ACTION__UPDATED);
}
/**
@@ -393,7 +439,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
if (mIsExpanded) {
// TODO: Save opened bubble & move it to top of stack
animateExpansion(false /* shouldExpand */);
- notifyExpansionChanged(mExpandedBubble, mIsExpanded);
+ notifyExpansionChanged(mExpandedBubble.entry, mIsExpanded);
logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
}
}
@@ -412,8 +458,8 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
@MainThread
public void expandStack() {
if (!mIsExpanded) {
- mExpandedBubble = getTopBubble();
- setExpandedBubble(mExpandedBubble);
+ String expandedBubbleKey = getBubbleAt(0).getKey();
+ setExpandedBubble(expandedBubbleKey);
logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__STACK_EXPANDED);
}
}
@@ -459,7 +505,8 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
final float yStart = Math.min(
mStackAnimationController.getStackPosition().y,
mExpandedAnimateYDistance);
- final float yDest = getStatusBarHeight() + mExpandedBubble.getHeight() + mBubblePadding;
+ final float yDest = getStatusBarHeight()
+ + mExpandedBubble.iconView.getHeight() + mBubblePadding;
if (shouldExpand) {
mExpandedViewContainer.setTranslationX(xStart);
@@ -484,17 +531,12 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
+ mBubbleContainer.getPaddingStart();
}
- private void notifyExpansionChanged(BubbleView bubbleView, boolean expanded) {
+ private void notifyExpansionChanged(NotificationEntry entry, boolean expanded) {
if (mExpandListener != null) {
- NotificationEntry entry = bubbleView != null ? bubbleView.getEntry() : null;
mExpandListener.onBubbleExpandChanged(expanded, entry != null ? entry.key : null);
}
}
- private BubbleView getTopBubble() {
- return getBubbleAt(0);
- }
-
/** Return the BubbleView at the given index from the bubble container. */
public BubbleView getBubbleAt(int i) {
return mBubbleContainer.getChildCount() > i
@@ -639,7 +681,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
if (getRootWindowInsets() != null) {
WindowInsets insets = getRootWindowInsets();
return Math.max(
- insets.getSystemWindowInsetTop(),
+ mStatusBarHeight,
insets.getDisplayCutout() != null
? insets.getDisplayCutout().getSafeInsetTop()
: 0);
@@ -665,31 +707,11 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
}
private void updateExpandedBubble() {
- if (mExpandedBubble == null) {
- return;
- }
-
- mExpandedViewContainer.setEntry(mExpandedBubble.getEntry(), this);
- if (mExpandedBubble.hasAppOverlayIntent()) {
- // Bubble with activity view expanded state
- ActivityView expandedView = mExpandedBubble.getActivityView();
- // XXX: gets added to linear layout
- expandedView.setLayoutParams(new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT, mExpandedBubbleHeight));
-
- mExpandedViewContainer.setExpandedView(expandedView);
- } else {
- // Bubble with notification view expanded state
- ExpandableNotificationRow row = mExpandedBubble.getRowView();
- if (row.getParent() != null) {
- // Row might still be in the shade when we expand
- ((ViewGroup) row.getParent()).removeView(row);
- }
- if (mIsExpanded) {
- mExpandedViewContainer.setExpandedView(row);
- } else {
- mExpandedViewContainer.setExpandedView(null);
- }
+ mExpandedViewContainer.removeAllViews();
+ if (mExpandedBubble != null && mIsExpanded) {
+ mExpandedViewContainer.addView(mExpandedBubble.expandedView);
+ mExpandedBubble.expandedView.populateActivityView();
+ mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
}
}
@@ -697,18 +719,10 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
Log.d(TAG, "applyCurrentState: mIsExpanded=" + mIsExpanded);
mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
- if (!mIsExpanded) {
- mExpandedViewContainer.setExpandedView(null);
- } else {
- View expandedView = mExpandedViewContainer.getExpandedView();
- if (expandedView instanceof ActivityView) {
- if (expandedView.isAttachedToWindow()) {
- ((ActivityView) expandedView).onLocationChanged();
- }
- } else {
- applyRowState(mExpandedBubble.getRowView());
- }
+ if (mIsExpanded) {
+ mExpandedBubble.expandedView.updateView();
}
+
int bubbsCount = mBubbleContainer.getChildCount();
for (int i = 0; i < bubbsCount; i++) {
BubbleView bv = (BubbleView) mBubbleContainer.getChildAt(i);
@@ -730,68 +744,34 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
private void updatePointerPosition() {
if (mExpandedBubble != null) {
- float pointerPosition = mExpandedBubble.getPosition().x
- + (mExpandedBubble.getWidth() / 2f);
- mExpandedViewContainer.setPointerPosition((int) pointerPosition);
+ float pointerPosition = mExpandedBubble.iconView.getPosition().x
+ + (mExpandedBubble.iconView.getWidth() / 2f);
+ mExpandedBubble.expandedView.setPointerPosition(pointerPosition);
}
}
- private void applyRowState(ExpandableNotificationRow view) {
- view.reset();
- view.setHeadsUp(false);
- view.resetTranslation();
- view.setOnKeyguard(false);
- view.setOnAmbient(false);
- view.setClipBottomAmount(0);
- view.setClipTopAmount(0);
- view.setContentTransformationAmount(0, false);
- view.setIconsVisible(true);
-
- // TODO - Need to reset this (and others) when view goes back in shade, leave for now
- // view.setTopRoundness(1, false);
- // view.setBottomRoundness(1, false);
-
- ExpandableViewState viewState = view.getViewState();
- viewState = viewState == null ? new ExpandableViewState() : viewState;
- viewState.height = view.getIntrinsicHeight();
- viewState.gone = false;
- viewState.hidden = false;
- viewState.dimmed = false;
- viewState.dark = false;
- viewState.alpha = 1f;
- viewState.notGoneIndex = -1;
- viewState.xTranslation = 0;
- viewState.yTranslation = 0;
- viewState.zTranslation = 0;
- viewState.scaleX = 1;
- viewState.scaleY = 1;
- viewState.inShelf = true;
- viewState.headsUpIsVisible = false;
- viewState.applyToView(view);
- }
-
/**
* @return the number of bubbles in the stack view.
*/
- private int getBubbleCount() {
+ public int getBubbleCount() {
return mBubbleContainer.getChildCount();
}
/**
* Finds the bubble index within the stack.
*
- * @param bubbleView the view of the bubble.
+ * @param bubble the bubble to look up.
* @return the index of the bubble view within the bubble stack. The range of the position
* is between 0 and the bubble count minus 1.
*/
- private int getBubbleIndex(BubbleView bubbleView) {
- return mBubbleContainer.indexOfChild(bubbleView);
+ int getBubbleIndex(Bubble bubble) {
+ return mBubbleContainer.indexOfChild(bubble.iconView);
}
/**
* @return the normalized x-axis position of the bubble stack rounded to 4 decimal places.
*/
- private float getNormalizedXPosition() {
+ public float getNormalizedXPosition() {
return new BigDecimal(getPosition().x / mDisplaySize.x)
.setScale(4, RoundingMode.CEILING.HALF_UP)
.floatValue();
@@ -800,7 +780,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
/**
* @return the normalized y-axis position of the bubble stack rounded to 4 decimal places.
*/
- private float getNormalizedYPosition() {
+ public float getNormalizedYPosition() {
return new BigDecimal(getPosition().y / mDisplaySize.y)
.setScale(4, RoundingMode.CEILING.HALF_UP)
.floatValue();
@@ -813,7 +793,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
* the user interaction is not specific to one bubble.
* @param action the user interaction enum.
*/
- private void logBubbleEvent(@Nullable BubbleView bubble, int action) {
+ private void logBubbleEvent(@Nullable Bubble bubble, int action) {
if (bubble == null) {
StatsLog.write(StatsLog.BUBBLE_UI_CHANGED,
null /* package name */,
@@ -825,7 +805,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
getNormalizedXPosition(),
getNormalizedYPosition());
} else {
- StatusBarNotification notification = bubble.getEntry().notification;
+ StatusBarNotification notification = bubble.entry.notification;
StatsLog.write(StatsLog.BUBBLE_UI_CHANGED,
notification.getPackageName(),
notification.getNotification().getChannelId(),
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
index 22cd2fcc3e72..7d3c0f85c0f7 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
@@ -188,7 +188,7 @@ class BubbleTouchHandler implements View.OnTouchListener {
} else {
stack.onBubbleDragFinish(mBubbleDraggingOut, x, y, velX, velY);
}
- } else if (floatingView.equals(stack.getExpandedBubble())) {
+ } else if (floatingView.equals(stack.getExpandedBubbleView())) {
stack.collapseStack();
} else if (isBubbleStack) {
if (stack.isExpanded()) {
@@ -197,7 +197,7 @@ class BubbleTouchHandler implements View.OnTouchListener {
stack.expandStack();
}
} else {
- stack.setExpandedBubble((BubbleView) floatingView);
+ stack.setExpandedBubble(((BubbleView) floatingView).getKey());
}
cleanUpDismissTarget();
mVelocityTracker.recycle();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
index 74ddc8f6b8fc..1a4b19940e34 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
@@ -17,13 +17,9 @@
package com.android.systemui.bubbles;
import android.annotation.Nullable;
-import android.app.ActivityView;
import android.app.Notification;
-import android.app.PendingIntent;
import android.content.Context;
import android.graphics.Color;
-import android.graphics.Insets;
-import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -31,16 +27,10 @@ import android.graphics.drawable.Icon;
import android.graphics.drawable.InsetDrawable;
import android.graphics.drawable.LayerDrawable;
import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowInsets;
import android.widget.FrameLayout;
-import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.internal.graphics.ColorUtils;
-import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -62,11 +52,6 @@ public class BubbleView extends FrameLayout implements BubbleTouchHandler.Floati
private int mIconInset;
private NotificationEntry mEntry;
- private PendingIntent mAppOverlayIntent;
- private BubbleController mBubbleController;
- private ActivityView mActivityView;
- private boolean mActivityViewReady;
- private boolean mActivityViewStarted;
public BubbleView(Context context) {
this(context, null);
@@ -86,7 +71,6 @@ public class BubbleView extends FrameLayout implements BubbleTouchHandler.Floati
// XXX: can this padding just be on the view and we look it up?
mPadding = getResources().getDimensionPixelSize(R.dimen.bubble_view_padding);
mIconInset = getResources().getDimensionPixelSize(R.dimen.bubble_icon_inset);
- mBubbleController = Dependency.get(BubbleController.class);
}
@Override
@@ -168,7 +152,6 @@ public class BubbleView extends FrameLayout implements BubbleTouchHandler.Floati
updateViews();
}
-
/**
* @return the {@link ExpandableNotificationRow} view to display notification content when the
* bubble is expanded.
@@ -235,88 +218,6 @@ public class BubbleView extends FrameLayout implements BubbleTouchHandler.Floati
return ColorUtils.blendARGB(defaultTint, Color.WHITE, WHITE_SCRIM_ALPHA);
}
- /**
- * @return a view used to display app overlay content when expanded.
- */
- public ActivityView getActivityView() {
- if (mActivityView == null) {
- mActivityView = new ActivityView(mContext, null /* attrs */, 0 /* defStyle */,
- true /* singleTaskInstance */);
- Log.d(TAG, "[getActivityView] created: " + mActivityView);
- mActivityView.setCallback(new ActivityView.StateCallback() {
- @Override
- public void onActivityViewReady(ActivityView view) {
- mActivityViewReady = true;
- mActivityView.startActivity(mAppOverlayIntent);
- }
-
- @Override
- public void onActivityViewDestroyed(ActivityView view) {
- mActivityViewReady = false;
- }
-
- /**
- * This is only called for tasks on this ActivityView, which is also set to
- * single-task mode -- meaning never more than one task on this display. If a task
- * is being removed, it's the top Activity finishing and this bubble should
- * be removed or collapsed.
- */
- @Override
- public void onTaskRemovalStarted(int taskId) {
- if (mEntry != null) {
- // Must post because this is called from a binder thread.
- post(() -> mBubbleController.removeBubble(mEntry.key));
- }
- }
- });
- mActivityView.setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
- ActivityView activityView = (ActivityView) view;
- // Here we assume that the position of the ActivityView on the screen
- // remains regardless of IME status. When we move ActivityView, the
- // forwardedInsets should be computed not against the current location
- // and size, but against the post-moved location and size.
- Point displaySize = new Point();
- view.getContext().getDisplay().getSize(displaySize);
- int[] windowLocation = view.getLocationOnScreen();
- final int windowBottom = windowLocation[1] + view.getHeight();
- final int keyboardHeight = insets.getSystemWindowInsetBottom()
- - insets.getStableInsetBottom();
- final int insetsBottom = Math.max(0,
- windowBottom + keyboardHeight - displaySize.y);
- activityView.setForwardedInsets(Insets.of(0, 0, 0, insetsBottom));
- return view.onApplyWindowInsets(insets);
- });
-
- }
- return mActivityView;
- }
-
- /**
- * Removes and releases an ActivityView if one was previously created for this bubble.
- */
- public void destroyActivityView(ViewGroup tmpParent) {
- if (mActivityView == null) {
- return;
- }
- if (!mActivityViewReady) {
- // release not needed, never initialized?
- mActivityView = null;
- return;
- }
- // HACK: release() will crash if the view is not attached.
- if (!mActivityView.isAttachedToWindow()) {
- mActivityView.setVisibility(View.GONE);
- tmpParent.addView(mActivityView, new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
- }
-
- mActivityView.release();
-
- ((ViewGroup) mActivityView.getParent()).removeView(mActivityView);
- mActivityView = null;
- }
-
@Override
public void setPosition(float x, float y) {
setPositionX(x);
@@ -337,20 +238,4 @@ public class BubbleView extends FrameLayout implements BubbleTouchHandler.Floati
public PointF getPosition() {
return new PointF(getTranslationX(), getTranslationY());
}
-
- /**
- * @return whether an ActivityView should be used to display the content of this Bubble
- */
- public boolean hasAppOverlayIntent() {
- return mAppOverlayIntent != null;
- }
-
- public PendingIntent getAppOverlayIntent() {
- return mAppOverlayIntent;
-
- }
-
- public void setBubbleIntent(PendingIntent intent) {
- mAppOverlayIntent = intent;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index 164406494250..5b158e906356 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -16,6 +16,7 @@
package com.android.systemui.bubbles.animation;
+import android.content.res.Resources;
import android.graphics.PointF;
import android.view.View;
import android.view.WindowInsets;
@@ -55,16 +56,19 @@ public class ExpandedAnimationController
private float mBubblePaddingPx;
/** Size of each bubble. */
private float mBubbleSizePx;
+ /** Height of the status bar. */
+ private float mStatusBarHeight;
@Override
protected void setLayout(PhysicsAnimationLayout layout) {
super.setLayout(layout);
- mStackOffsetPx = layout.getResources().getDimensionPixelSize(
- R.dimen.bubble_stack_offset);
- mBubblePaddingPx = layout.getResources().getDimensionPixelSize(
- R.dimen.bubble_padding);
- mBubbleSizePx = layout.getResources().getDimensionPixelSize(
- R.dimen.individual_bubble_size);
+
+ final Resources res = layout.getResources();
+ mStackOffsetPx = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
+ mBubblePaddingPx = res.getDimensionPixelSize(R.dimen.bubble_padding);
+ mBubbleSizePx = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
+ mStatusBarHeight =
+ res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
}
/**
@@ -103,7 +107,7 @@ public class ExpandedAnimationController
final WindowInsets insets = mLayout.getRootWindowInsets();
if (insets != null) {
return mBubblePaddingPx + Math.max(
- insets.getSystemWindowInsetTop(),
+ mStatusBarHeight,
insets.getDisplayCutout() != null
? insets.getDisplayCutout().getSafeInsetTop()
: 0);
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 0c089a75aece..7dfb21cf384f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -16,15 +16,12 @@
package com.android.systemui.bubbles.animation;
-import android.content.Context;
import android.content.res.Resources;
-import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.Log;
import android.view.View;
import android.view.WindowInsets;
-import android.view.WindowManager;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.FlingAnimation;
@@ -88,9 +85,8 @@ public class StackAnimationController extends
private int mBubbleOffscreen;
/** How far down the screen the stack starts, when there is no pre-existing location. */
private int mStackStartingVerticalOffset;
-
- private Point mDisplaySize;
- private RectF mAllowableStackPositionRegion;
+ /** Height of the status bar. */
+ private float mStatusBarHeight;
@Override
protected void setLayout(PhysicsAnimationLayout layout) {
@@ -103,11 +99,8 @@ public class StackAnimationController extends
mBubbleOffscreen = res.getDimensionPixelSize(R.dimen.bubble_stack_offscreen);
mStackStartingVerticalOffset =
res.getDimensionPixelSize(R.dimen.bubble_stack_starting_offset_y);
-
- mDisplaySize = new Point();
- WindowManager wm =
- (WindowManager) layout.getContext().getSystemService(Context.WINDOW_SERVICE);
- wm.getDefaultDisplay().getSize(mDisplaySize);
+ mStatusBarHeight =
+ res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
}
/**
@@ -203,10 +196,9 @@ public class StackAnimationController extends
*/
public RectF getAllowableStackPositionRegion() {
final WindowInsets insets = mLayout.getRootWindowInsets();
- mAllowableStackPositionRegion = new RectF();
-
+ final RectF allowableRegion = new RectF();
if (insets != null) {
- mAllowableStackPositionRegion.left =
+ allowableRegion.left =
-mBubbleOffscreen
- mBubblePadding
+ Math.max(
@@ -214,7 +206,7 @@ public class StackAnimationController extends
insets.getDisplayCutout() != null
? insets.getDisplayCutout().getSafeInsetLeft()
: 0);
- mAllowableStackPositionRegion.right =
+ allowableRegion.right =
mLayout.getWidth()
- mIndividualBubbleSize
+ mBubbleOffscreen
@@ -222,17 +214,17 @@ public class StackAnimationController extends
- Math.max(
insets.getSystemWindowInsetRight(),
insets.getDisplayCutout() != null
- ? insets.getDisplayCutout().getSafeInsetRight()
- : 0);
+ ? insets.getDisplayCutout().getSafeInsetRight()
+ : 0);
- mAllowableStackPositionRegion.top =
+ allowableRegion.top =
mBubblePadding
+ Math.max(
- insets.getSystemWindowInsetTop(),
+ mStatusBarHeight,
insets.getDisplayCutout() != null
- ? insets.getDisplayCutout().getSafeInsetTop()
- : 0);
- mAllowableStackPositionRegion.bottom =
+ ? insets.getDisplayCutout().getSafeInsetTop()
+ : 0);
+ allowableRegion.bottom =
mLayout.getHeight()
- mIndividualBubbleSize
- mBubblePadding
@@ -243,7 +235,7 @@ public class StackAnimationController extends
: 0);
}
- return mAllowableStackPositionRegion;
+ return allowableRegion;
}
@Override
@@ -287,31 +279,14 @@ public class StackAnimationController extends
@Override
void onChildAdded(View child, int index) {
- // If this is the first child added, position the stack in its starting position.
if (mLayout.getChildCount() == 1) {
- moveStackToStartPosition();
- }
-
- if (mLayout.indexOfChild(child) == 0) {
- child.setTranslationY(mStackPosition.y);
-
- // Pop in the new bubble.
- child.setScaleX(ANIMATE_IN_STARTING_SCALE);
- child.setScaleY(ANIMATE_IN_STARTING_SCALE);
- mLayout.animateValueForChildAtIndex(DynamicAnimation.SCALE_X, 0, 1f);
- mLayout.animateValueForChildAtIndex(DynamicAnimation.SCALE_Y, 0, 1f);
-
- // Fade in the new bubble.
- child.setAlpha(0);
- mLayout.animateValueForChildAtIndex(DynamicAnimation.ALPHA, 0, 1f);
-
- // Start the new bubble 4x the normal offset distance in the opposite direction. We'll
- // animate in from this position. Since the animations are chained, when the new bubble
- // flies in from the side, it will push the other ones out of the way.
- float xOffset = getOffsetForChainedPropertyAnimation(DynamicAnimation.TRANSLATION_X);
- child.setTranslationX(mStackPosition.x - ANIMATE_TRANSLATION_FACTOR * xOffset);
- mLayout.animateValueForChildAtIndex(
- DynamicAnimation.TRANSLATION_X, 0, mStackPosition.x);
+ // If this is the first child added, position the stack in its starting position before
+ // animating in.
+ moveStackToStartPosition(() -> animateInBubble(child));
+ } else if (mLayout.indexOfChild(child) == 0) {
+ // Otherwise, animate the bubble in if it's the newest bubble. If we're adding a bubble
+ // to the back of the stack, it'll be largely invisible so don't bother animating it in.
+ animateInBubble(child);
}
}
@@ -334,10 +309,14 @@ public class StackAnimationController extends
}
/** Moves the stack, without any animation, to the starting position. */
- private void moveStackToStartPosition() {
- mLayout.post(() -> setStackPosition(
- getAllowableStackPositionRegion().right,
- getAllowableStackPositionRegion().top + mStackStartingVerticalOffset));
+ private void moveStackToStartPosition(Runnable after) {
+ // Post to ensure that the layout's width and height have been calculated.
+ mLayout.post(() -> {
+ setStackPosition(
+ getAllowableStackPositionRegion().right,
+ getAllowableStackPositionRegion().top + mStackStartingVerticalOffset);
+ after.run();
+ });
}
/**
@@ -379,6 +358,29 @@ public class StackAnimationController extends
}
}
+ /** Animates in the given bubble. */
+ private void animateInBubble(View child) {
+ child.setTranslationY(mStackPosition.y);
+
+ // Pop in the new bubble.
+ child.setScaleX(ANIMATE_IN_STARTING_SCALE);
+ child.setScaleY(ANIMATE_IN_STARTING_SCALE);
+ mLayout.animateValueForChildAtIndex(DynamicAnimation.SCALE_X, 0, 1f);
+ mLayout.animateValueForChildAtIndex(DynamicAnimation.SCALE_Y, 0, 1f);
+
+ // Fade in the new bubble.
+ child.setAlpha(0);
+ mLayout.animateValueForChildAtIndex(DynamicAnimation.ALPHA, 0, 1f);
+
+ // Start the new bubble 4x the normal offset distance in the opposite direction. We'll
+ // animate in from this position. Since the animations are chained, when the new bubble
+ // flies in from the side, it will push the other ones out of the way.
+ float xOffset = getOffsetForChainedPropertyAnimation(DynamicAnimation.TRANSLATION_X);
+ child.setTranslationX(mStackPosition.x - ANIMATE_TRANSLATION_FACTOR * xOffset);
+ mLayout.animateValueForChildAtIndex(
+ DynamicAnimation.TRANSLATION_X, 0, mStackPosition.x);
+ }
+
/**
* Springs the first bubble to the given final position, with the rest of the stack 'following'.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
index fdf18ce24f50..900ea72d856c 100644
--- a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
+++ b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
@@ -48,6 +48,7 @@ import javax.inject.Singleton;
@Singleton
public class SysuiColorExtractor extends ColorExtractor implements Dumpable {
private static final String TAG = "SysuiColorExtractor";
+ private final Tonal mTonal;
private boolean mWallpaperVisible;
private boolean mHasBackdrop;
// Colors to return when the wallpaper isn't visible
@@ -61,6 +62,7 @@ public class SysuiColorExtractor extends ColorExtractor implements Dumpable {
@VisibleForTesting
public SysuiColorExtractor(Context context, ExtractionType type, boolean registerVisibility) {
super(context, type);
+ mTonal = type instanceof Tonal ? (Tonal) type : new Tonal(context);
mWpHiddenColors = new GradientColors();
WallpaperColors systemColors = getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
@@ -94,7 +96,7 @@ public class SysuiColorExtractor extends ColorExtractor implements Dumpable {
}
private void updateDefaultGradients(WallpaperColors colors) {
- Tonal.applyFallback(colors, mWpHiddenColors);
+ mTonal.applyFallback(colors, mWpHiddenColors);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeReceiver.java b/packages/SystemUI/src/com/android/systemui/doze/DozeReceiver.java
index 4a2e06c058cb..f5cf149ba868 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeReceiver.java
@@ -25,9 +25,4 @@ public interface DozeReceiver {
* Invoked every time a minute is elapsed in doze mode
*/
void dozeTimeTick();
-
- /**
- * When view is double tapped in doze mode.
- */
- void onDozeDoubleTap();
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 5efdc2f61d76..2d1dba6f79c8 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -131,7 +131,7 @@ public class DozeSensors {
new PluginSensor(
new SensorManagerPlugin.Sensor(TYPE_WAKE_LOCK_SCREEN),
Settings.Secure.DOZE_WAKE_SCREEN_GESTURE,
- mConfig.wakeScreenGestureAvailable(),
+ mConfig.wakeScreenGestureAvailable() && alwaysOn,
DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN,
false /* reports touch coordinates */,
false /* touchscreen */),
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 873fbc226629..e207cb13d311 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -161,7 +161,8 @@ public class DozeTriggers implements DozeMachine.Part {
} else {
mDozeHost.extendPulse();
}
- }, sensorPerformedProxCheck || mDockManager.isDocked(), pulseReason);
+ }, sensorPerformedProxCheck
+ || (mDockManager != null && mDockManager.isDocked()), pulseReason);
}
if (isPickup) {
@@ -224,7 +225,9 @@ public class DozeTriggers implements DozeMachine.Part {
case INITIALIZED:
mBroadcastReceiver.register(mContext);
mDozeHost.addCallback(mHostCallback);
- mDockManager.addListener(mDockEventListener);
+ if (mDockManager != null) {
+ mDockManager.addListener(mDockEventListener);
+ }
checkTriggersAtInit();
break;
case DOZE:
@@ -250,7 +253,9 @@ public class DozeTriggers implements DozeMachine.Part {
case FINISH:
mBroadcastReceiver.unregister(mContext);
mDozeHost.removeCallback(mHostCallback);
- mDockManager.removeListener(mDockEventListener);
+ if (mDockManager != null) {
+ mDockManager.removeListener(mDockEventListener);
+ }
mDozeSensors.setListening(false);
mDozeSensors.setProxListening(false);
break;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index f5ac0d39d61f..7c9b2864f7f2 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -33,6 +33,7 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.UserInfo;
+import android.content.res.Configuration;
import android.database.ContentObserver;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
@@ -91,6 +92,7 @@ import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.EmergencyDialerConstants;
+import com.android.systemui.util.leak.RotationUtils;
import com.android.systemui.volume.SystemUIInterpolators.LogAccelerateInterpolator;
import java.util.ArrayList;
@@ -159,6 +161,8 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private final ScreenshotHelper mScreenshotHelper;
private final ScreenRecordHelper mScreenRecordHelper;
+ private int mLastRotation;
+
/**
* @param context everything needs a context :(
*/
@@ -201,6 +205,8 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mScreenshotHelper = new ScreenshotHelper(context);
mScreenRecordHelper = new ScreenRecordHelper(context);
+ mLastRotation = RotationUtils.getRotation(mContext);
+
Dependency.get(ConfigurationController.class).addCallback(this);
}
@@ -426,6 +432,15 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mContext.getTheme().applyStyle(mContext.getThemeResId(), true);
}
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ int rotation = RotationUtils.getRotation(mContext);
+ if (rotation != mLastRotation) {
+ mDialog.onRotate();
+ }
+ mLastRotation = rotation;
+ }
+
public void destroy() {
Dependency.get(ConfigurationController.class).removeCallback(this);
}
@@ -1091,7 +1106,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
protected int getActionLayoutId(Context context) {
- if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.GLOBAL_ACTIONS_GRID_ENABLED)) {
+ if (isGridEnabled(context)) {
return com.android.systemui.R.layout.global_actions_grid_item;
}
return com.android.systemui.R.layout.global_actions_item;
@@ -1465,7 +1480,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private final Context mContext;
private final MyAdapter mAdapter;
- private final MultiListLayout mGlobalActionsLayout;
+ private MultiListLayout mGlobalActionsLayout;
private final OnClickListener mClickListener;
private final OnItemLongClickListener mLongClickListener;
private final GradientDrawable mGradientDrawable;
@@ -1505,8 +1520,13 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
window.setBackgroundDrawable(mGradientDrawable);
window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
+ initializeLayout();
- setContentView(getGlobalActionsLayoutId(context));
+ setTitle(R.string.global_actions);
+ }
+
+ private void initializeLayout() {
+ setContentView(getGlobalActionsLayoutId(mContext));
mGlobalActionsLayout = (MultiListLayout)
findViewById(com.android.systemui.R.id.global_actions_view);
mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss());
@@ -1520,11 +1540,20 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
return true;
}
});
- setTitle(R.string.global_actions);
+ }
+
+ public void onRotate() {
+ if (mShowing && isGridEnabled(mContext)) {
+ initializeLayout();
+ updateList();
+ }
}
private int getGlobalActionsLayoutId(Context context) {
- if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.GLOBAL_ACTIONS_GRID_ENABLED)) {
+ if (isGridEnabled(context)) {
+ if (RotationUtils.getRotation(context) == RotationUtils.ROTATION_SEASCAPE) {
+ return com.android.systemui.R.layout.global_actions_grid_seascape;
+ }
return com.android.systemui.R.layout.global_actions_grid;
}
return com.android.systemui.R.layout.global_actions_wrapped;
@@ -1543,10 +1572,20 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
int separatedIndex = separatedActions.indexOf(action);
ViewGroup parent;
if (separatedIndex != -1) {
- parent = mGlobalActionsLayout.getParentView(true, separatedIndex);
+ parent = mGlobalActionsLayout.getParentView(true, separatedIndex, false);
} else {
+ boolean reverse = false;
+
+ // If we're using the grid layout and we're in seascape, reverse the order
+ // of sublists to make sure they render in the correct positions,
+ // since we can't reverse vertical LinearLayouts through the layout xml.
+
+ if (isGridEnabled(mContext) && RotationUtils.getRotation(mContext)
+ == RotationUtils.ROTATION_SEASCAPE) {
+ reverse = true;
+ }
int listIndex = listActions.indexOf(action);
- parent = mGlobalActionsLayout.getParentView(false, listIndex);
+ parent = mGlobalActionsLayout.getParentView(false, listIndex, reverse);
}
View v = mAdapter.getView(i, null, parent);
final int pos = i;
@@ -1665,4 +1704,11 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mKeyguardShowing = keyguardShowing;
}
}
+
+ /**
+ * Determines whether or not the Global Actions Dialog should use the newer grid-style layout.
+ */
+ public static boolean isGridEnabled(Context context) {
+ return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.GLOBAL_ACTIONS_GRID_ENABLED);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
index 0e49b5f3cd2a..1d042776efc9 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
@@ -83,11 +83,11 @@ public class GlobalActionsGridLayout extends MultiListLayout {
}
@Override
- public ViewGroup getParentView(boolean separated, int index) {
+ public ViewGroup getParentView(boolean separated, int index, boolean reverseOrder) {
if (separated) {
return getSeparatedView();
} else {
- return getListView().getParentView(index);
+ return getListView().getParentView(index, reverseOrder);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
index 37755155751f..d5dcd74c7ea8 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
@@ -28,16 +28,13 @@ import android.widget.LinearLayout;
*
* * Try to maintain a 'square' grid (equal number of columns and rows) based on the expected item
* count.
+ * * Determine the position and parent of any item by its index and the total item count.
* * Display and hide sub-lists as needed, depending on the expected item count.
- * * Favor bias toward having more rows or columns depending on the orientation of the device
- * (TODO(123344999): Implement this, currently always favors adding more rows.)
- * * Change the orientation (horizontal vs. vertical) of the container and sub-lists to act as rows
- * or columns depending on the orientation of the device.
- * (TODO(123344999): Implement this, currently always columns.)
*
* While we could implement this behavior with a GridLayout, it would take significantly more
* time and effort, and would require more substantial refactoring of the existing code in
- * GlobalActionsDialog, since it would require manipulation of the child items themselves.
+ * GlobalActionsDialog, since it would require manipulation of layout properties on the child items
+ * themselves.
*
*/
@@ -65,14 +62,25 @@ public class ListGridLayout extends LinearLayout {
/**
* Get the parent view associated with the item which should be placed at the given position.
*/
- public ViewGroup getParentView(int index) {
- ViewGroup firstParent = (ViewGroup) getChildAt(0);
+ public ViewGroup getParentView(int index, boolean reverseSublists) {
if (mRows == 0) {
- return firstParent;
+ return null;
}
+ int column = getParentViewIndex(index, reverseSublists);
+ return (ViewGroup) getChildAt(column);
+ }
+
+ private int reverseSublistIndex(int index) {
+ return getChildCount() - (index + 1);
+ }
+
+ private int getParentViewIndex(int index, boolean reverseSublists) {
int column = (int) Math.floor(index / mRows);
- ViewGroup parent = (ViewGroup) getChildAt(column);
- return parent != null ? parent : firstParent;
+ int columnCount = getChildCount();
+ if (reverseSublists) {
+ column = reverseSublistIndex(column);
+ }
+ return column;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 684175cf4212..85d975f36db5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -25,7 +25,9 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.graphics.Rect;
import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.icu.text.DateFormat;
import android.icu.text.DisplayContext;
@@ -35,10 +37,13 @@ import android.os.Handler;
import android.os.Trace;
import android.provider.Settings;
import android.service.notification.ZenModeConfig;
-import android.text.Spannable;
import android.text.SpannableStringBuilder;
+import android.text.Spanned;
import android.text.TextUtils;
+import android.text.style.DynamicDrawableSpan;
+import android.text.style.ImageSpan;
import android.text.style.StyleSpan;
+import android.util.MathUtils;
import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
@@ -72,6 +77,8 @@ public class KeyguardSliceProvider extends SliceProvider implements
private static final StyleSpan BOLD_STYLE = new StyleSpan(Typeface.BOLD);
public static final String KEYGUARD_SLICE_URI = "content://com.android.systemui.keyguard/main";
+ private static final String KEYGUARD_HEADER_URI =
+ "content://com.android.systemui.keyguard/header";
public static final String KEYGUARD_DATE_URI = "content://com.android.systemui.keyguard/date";
public static final String KEYGUARD_NEXT_ALARM_URI =
"content://com.android.systemui.keyguard/alarm";
@@ -90,6 +97,7 @@ public class KeyguardSliceProvider extends SliceProvider implements
private static KeyguardSliceProvider sInstance;
protected final Uri mSliceUri;
+ protected final Uri mHeaderUri;
protected final Uri mDateUri;
protected final Uri mAlarmUri;
protected final Uri mDndUri;
@@ -163,6 +171,7 @@ public class KeyguardSliceProvider extends SliceProvider implements
KeyguardSliceProvider(Handler handler) {
mHandler = handler;
mSliceUri = Uri.parse(KEYGUARD_SLICE_URI);
+ mHeaderUri = Uri.parse(KEYGUARD_HEADER_URI);
mDateUri = Uri.parse(KEYGUARD_DATE_URI);
mAlarmUri = Uri.parse(KEYGUARD_NEXT_ALARM_URI);
mDndUri = Uri.parse(KEYGUARD_DND_URI);
@@ -213,26 +222,32 @@ public class KeyguardSliceProvider extends SliceProvider implements
protected void addMediaLocked(ListBuilder listBuilder) {
if (mMediaMetaData != null) {
SpannableStringBuilder builder = new SpannableStringBuilder();
+
+ Icon notificationIcon = mMediaManager == null ? null : mMediaManager.getMediaIcon();
+ if (notificationIcon != null) {
+ Drawable drawable = notificationIcon.loadDrawable(getContext());
+ Rect mediaBounds = new Rect(0 /* left */, 0 /* top */,
+ drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
+ int iconHeaderSize = getContext().getResources()
+ .getDimensionPixelSize(R.dimen.header_icon_size);
+ MathUtils.fitRect(mediaBounds, iconHeaderSize);
+ drawable.setBounds(mediaBounds);
+ builder.append("# ");
+ builder.setSpan(new ImageSpan(drawable, DynamicDrawableSpan.ALIGN_CENTER),
+ 0 /* start */, 1 /* end */, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+ }
+
CharSequence title = mMediaMetaData.getText(MediaMetadata.METADATA_KEY_TITLE);
if (TextUtils.isEmpty(title)) {
title = getContext().getResources().getString(R.string.music_controls_no_title);
}
builder.append(title);
- builder.setSpan(BOLD_STYLE, 0, title.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+ listBuilder.setHeader(new ListBuilder.HeaderBuilder(mHeaderUri).setTitle(builder));
CharSequence album = mMediaMetaData.getText(MediaMetadata.METADATA_KEY_ARTIST);
if (!TextUtils.isEmpty(album)) {
- builder.append(" ").append(album);
+ listBuilder.addRow(new RowBuilder(mMediaUri).setTitle(album));
}
-
- RowBuilder mediaBuilder = new RowBuilder(mMediaUri).setTitle(builder);
- Icon notificationIcon = mMediaManager == null ? null : mMediaManager.getMediaIcon();
- if (notificationIcon != null) {
- IconCompat icon = IconCompat.createFromIcon(notificationIcon);
- mediaBuilder.addEndItem(icon, ListBuilder.ICON_IMAGE);
- }
-
- listBuilder.addRow(mediaBuilder);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index ddd9cbf209d6..aebadf936e0c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -16,6 +16,7 @@
package com.android.systemui.media;
+import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -24,6 +25,7 @@ import android.media.AudioAttributes;
import android.media.IAudioService;
import android.media.IRingtonePlayer;
import android.media.Ringtone;
+import android.media.VolumeShaper;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
@@ -78,11 +80,16 @@ public class RingtonePlayer extends SystemUI {
private final Ringtone mRingtone;
public Client(IBinder token, Uri uri, UserHandle user, AudioAttributes aa) {
+ this(token, uri, user, aa, null);
+ }
+
+ Client(IBinder token, Uri uri, UserHandle user, AudioAttributes aa,
+ @Nullable VolumeShaper.Configuration volumeShaperConfig) {
mToken = token;
mRingtone = new Ringtone(getContextForUser(user), false);
mRingtone.setAudioAttributes(aa);
- mRingtone.setUri(uri);
+ mRingtone.setUri(uri, volumeShaperConfig);
}
@Override
@@ -99,6 +106,12 @@ public class RingtonePlayer extends SystemUI {
@Override
public void play(IBinder token, Uri uri, AudioAttributes aa, float volume, boolean looping)
throws RemoteException {
+ playWithVolumeShaping(token, uri, aa, volume, looping, null);
+ }
+ @Override
+ public void playWithVolumeShaping(IBinder token, Uri uri, AudioAttributes aa, float volume,
+ boolean looping, @Nullable VolumeShaper.Configuration volumeShaperConfig)
+ throws RemoteException {
if (LOGD) {
Log.d(TAG, "play(token=" + token + ", uri=" + uri + ", uid="
+ Binder.getCallingUid() + ")");
@@ -108,7 +121,7 @@ public class RingtonePlayer extends SystemUI {
client = mClients.get(token);
if (client == null) {
final UserHandle user = Binder.getCallingUserHandle();
- client = new Client(token, uri, user, aa);
+ client = new Client(token, uri, user, aa, volumeShaperConfig);
token.linkToDeath(client, 0);
mClients.put(token, client);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index 82aa4737af99..9c65994425ed 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -79,6 +79,7 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
private static final int MSG_RESIZE_IMMEDIATE = 1;
private static final int MSG_RESIZE_ANIMATE = 2;
+ private static final int MSG_OFFSET_ANIMATE = 3;
private Context mContext;
private IActivityManager mActivityManager;
@@ -360,9 +361,20 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
/**
* Animates the PiP to offset it from the IME or shelf.
*/
- void animateToOffset(Rect toBounds) {
+ void animateToOffset(Rect originalBounds, int offset) {
cancelAnimations();
- resizeAndAnimatePipUnchecked(toBounds, SHIFT_DURATION);
+ adjustAndAnimatePipOffset(originalBounds, offset, SHIFT_DURATION);
+ }
+
+ private void adjustAndAnimatePipOffset(Rect originalBounds, int offset, int duration) {
+ if (offset == 0) {
+ return;
+ }
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = originalBounds;
+ args.argi1 = offset;
+ args.argi2 = duration;
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_OFFSET_ANIMATE, args));
}
/**
@@ -549,6 +561,31 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
return true;
}
+ case MSG_OFFSET_ANIMATE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Rect originalBounds = (Rect) args.arg1;
+ final int offset = args.argi1;
+ final int duration = args.argi2;
+ try {
+ StackInfo stackInfo = mActivityTaskManager.getStackInfo(
+ WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
+ if (stackInfo == null) {
+ // In the case where we've already re-expanded or dismissed the PiP, then
+ // just skip the resize
+ return true;
+ }
+
+ mActivityTaskManager.offsetPinnedStackBounds(stackInfo.stackId, originalBounds,
+ 0/* xOffset */, offset, duration);
+ Rect toBounds = new Rect(originalBounds);
+ toBounds.offset(0, offset);
+ mBounds.set(toBounds);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not animate offset pinned stack with offset: " + offset, e);
+ }
+ return true;
+ }
+
default:
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 6a9f24c619fe..cef1b6b1d93b 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -346,12 +346,11 @@ public class PipTouchHandler {
}
private void animateToOffset(Rect animatingBounds, Rect toAdjustedBounds) {
- final Rect bounds = new Rect(animatingBounds);
- bounds.offset(0, toAdjustedBounds.bottom - bounds.top);
+ int offset = toAdjustedBounds.bottom - animatingBounds.top;
// In landscape mode, PIP window can go offset while launching IME. We want to align the
// the top of the PIP window with the top of the movement bounds in that case.
- bounds.offset(0, Math.max(0, mMovementBounds.top - bounds.top));
- mMotionHelper.animateToOffset(bounds);
+ offset += Math.max(0, mMovementBounds.top - animatingBounds.top);
+ mMotionHelper.animateToOffset(animatingBounds, offset);
}
private void onRegistrationChanged(boolean isRegistered) {
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index f0543454073d..c43f5728aaa2 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -54,6 +54,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.time.Duration;
import java.util.Arrays;
+import java.util.concurrent.Future;
public class PowerUI extends SystemUI {
static final String TAG = "PowerUI";
@@ -80,6 +81,7 @@ public class PowerUI extends SystemUI {
private Estimate mLastEstimate;
private boolean mLowWarningShownThisChargeCycle;
private boolean mSevereWarningShownThisChargeCycle;
+ private Future mLastShowWarningTask;
private int mLowBatteryAlertCloseLevel;
private final int[] mLowBatteryReminderLevels = new int[2];
@@ -247,7 +249,10 @@ public class PowerUI extends SystemUI {
}
// Show the correct version of low battery warning if needed
- ThreadUtils.postOnBackgroundThread(() -> {
+ if (mLastShowWarningTask != null) {
+ mLastShowWarningTask.cancel(true);
+ }
+ mLastShowWarningTask = ThreadUtils.postOnBackgroundThread(() -> {
maybeShowBatteryWarning(
oldBatteryLevel, plugged, oldPlugged, oldBucket, bucket);
});
@@ -276,7 +281,7 @@ public class PowerUI extends SystemUI {
estimate = mEnhancedEstimates.getEstimate();
mLastEstimate = estimate;
}
- // Turbo is not always booted once SysUI is running so we have ot make sure we actually
+ // Turbo is not always booted once SysUI is running so we have to make sure we actually
// get data back
if (estimate != null) {
mTimeRemaining = estimate.estimateMillis;
@@ -355,13 +360,26 @@ public class PowerUI extends SystemUI {
// Only show the low warning once per charge cycle & no battery saver
final boolean canShowWarning = !mLowWarningShownThisChargeCycle && !isPowerSaver
&& (timeRemaining < mEnhancedEstimates.getLowWarningThreshold()
- || mBatteryLevel <= warnLevel);
+ || mBatteryLevel <= warnLevel);
// Only show the severe warning once per charge cycle
final boolean canShowSevereWarning = !mSevereWarningShownThisChargeCycle
&& (timeRemaining < mEnhancedEstimates.getSevereWarningThreshold()
- || mBatteryLevel <= critLevel);
-
+ || mBatteryLevel <= critLevel);
+
+ final boolean canShow = canShowWarning || canShowSevereWarning;
+ if (DEBUG) {
+ Slog.d(TAG, "Enhanced trigger is: " + canShow + "\nwith values: "
+ + " mLowWarningShownThisChargeCycle: " + mLowWarningShownThisChargeCycle
+ + " mSevereWarningShownThisChargeCycle: " + mSevereWarningShownThisChargeCycle
+ + " mEnhancedEstimates.timeremaining: " + timeRemaining
+ + " mBatteryLevel: " + mBatteryLevel
+ + " canShowWarning: " + canShowWarning
+ + " canShowSevereWarning: " + canShowSevereWarning
+ + " plugged: " + plugged
+ + " batteryStatus: " + batteryStatus
+ + " isPowerSaver: " + isPowerSaver);
+ }
return canShowWarning || canShowSevereWarning;
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
index 65ed889f34e1..1765dc866c66 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
@@ -16,11 +16,14 @@ package com.android.systemui.privacy
import android.content.Context
import android.util.AttributeSet
+import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
+import com.android.systemui.Dependency
import com.android.systemui.R
+import com.android.systemui.statusbar.policy.KeyguardMonitor
class OngoingPrivacyChip @JvmOverloads constructor(
context: Context,
@@ -29,14 +32,27 @@ class OngoingPrivacyChip @JvmOverloads constructor(
defStyleRes: Int = 0
) : LinearLayout(context, attrs, defStyleAttrs, defStyleRes) {
- private val iconMargin =
- context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_margin)
+ private val iconMarginExpanded = context.resources.getDimensionPixelSize(
+ R.dimen.ongoing_appops_chip_icon_margin_expanded)
+ private val iconMarginCollapsed = context.resources.getDimensionPixelSize(
+ R.dimen.ongoing_appops_chip_icon_margin_collapsed)
private val iconSize =
context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_size)
- val iconColor = context.resources.getColor(
+ private val iconColor = context.resources.getColor(
R.color.status_bar_clock_color, context.theme)
+ private val backgroundDrawable = context.getDrawable(R.drawable.privacy_chip_bg)
private lateinit var text: TextView
private lateinit var iconsContainer: LinearLayout
+ private lateinit var inUseText: TextView
+ var expanded = false
+ set(value) {
+ if (value != field) {
+ field = value
+ updateView()
+ }
+ }
+ @Suppress("DEPRECATION")
+ private val keyguardMonitor = Dependency.get(KeyguardMonitor::class.java)
var builder = PrivacyDialogBuilder(context, emptyList<PrivacyItem>())
var privacyList = emptyList<PrivacyItem>()
set(value) {
@@ -48,15 +64,18 @@ class OngoingPrivacyChip @JvmOverloads constructor(
override fun onFinishInflate() {
super.onFinishInflate()
+ inUseText = findViewById(R.id.in_use_text)
text = findViewById(R.id.text_container)
iconsContainer = findViewById(R.id.icons_container)
}
// Should only be called if the builder icons or app changed
private fun updateView() {
+ inUseText.visibility = if (expanded) View.GONE else View.VISIBLE
+ background = if (expanded) backgroundDrawable else null
fun setIcons(dialogBuilder: PrivacyDialogBuilder, iconsContainer: ViewGroup) {
iconsContainer.removeAllViews()
- dialogBuilder.generateIcons().forEach {
+ dialogBuilder.generateIcons().forEachIndexed { i, it ->
it.mutate()
it.setTint(iconColor)
val image = ImageView(context).apply {
@@ -64,25 +83,18 @@ class OngoingPrivacyChip @JvmOverloads constructor(
scaleType = ImageView.ScaleType.CENTER_INSIDE
}
iconsContainer.addView(image, iconSize, iconSize)
- val lp = image.layoutParams as MarginLayoutParams
- lp.marginStart = iconMargin
- image.layoutParams = lp
+ if (i != 0) {
+ val lp = image.layoutParams as MarginLayoutParams
+ lp.marginStart = if (expanded) iconMarginExpanded else iconMarginCollapsed
+ image.layoutParams = lp
+ }
}
}
if (!privacyList.isEmpty()) {
generateContentDescription()
setIcons(builder, iconsContainer)
- text.visibility = if (builder.types.size == 1) VISIBLE else GONE
- if (builder.types.size == 1) {
- if (builder.app != null) {
- text.setText(builder.app?.applicationName)
- } else {
- text.text = context.resources.getQuantityString(
- R.plurals.ongoing_privacy_chip_multiple_apps,
- builder.appsAndTypes.size, builder.appsAndTypes.size)
- }
- }
+ setApplicationText()
} else {
text.visibility = GONE
iconsContainer.removeAllViews()
@@ -90,13 +102,28 @@ class OngoingPrivacyChip @JvmOverloads constructor(
requestLayout()
}
+ private fun setApplicationText() {
+ text.visibility = if (builder.types.size == 1 && expanded) VISIBLE else GONE
+ if (builder.types.size == 1 && expanded) {
+ if (builder.app != null && !amISecure()) {
+ text.setText(builder.app?.applicationName)
+ } else {
+ text.text = context.resources.getQuantityString(
+ R.plurals.ongoing_privacy_chip_multiple_apps,
+ builder.appsAndTypes.size, builder.appsAndTypes.size)
+ }
+ }
+ }
+
+ private fun amISecure() = keyguardMonitor.isShowing && keyguardMonitor.isSecure
+
private fun generateContentDescription() {
val typesText = builder.joinTypes()
if (builder.types.size > 1) {
contentDescription = context.getString(
R.string.ongoing_privacy_chip_content_multiple_apps, typesText)
} else {
- if (builder.app != null) {
+ if (builder.app != null && !amISecure()) {
contentDescription =
context.getString(R.string.ongoing_privacy_chip_content_single_app,
builder.app?.applicationName, typesText)
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
index cff7fe449be1..75b8a056df1d 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
@@ -36,8 +36,8 @@ import com.android.systemui.plugins.ActivityStarter
import java.util.concurrent.TimeUnit
class OngoingPrivacyDialog constructor(
- val context: Context,
- val dialogBuilder: PrivacyDialogBuilder
+ private val context: Context,
+ private val dialogBuilder: PrivacyDialogBuilder
) {
private val iconSize = context.resources.getDimensionPixelSize(
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt
index 9c1076af9ede..bbea6b277e90 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt
@@ -18,7 +18,7 @@ import android.content.Context
import android.graphics.drawable.Drawable
import com.android.systemui.R
-class PrivacyDialogBuilder(val context: Context, itemsList: List<PrivacyItem>) {
+class PrivacyDialogBuilder(private val context: Context, itemsList: List<PrivacyItem>) {
val appsAndTypes: List<Pair<PrivacyApplication, List<PrivacyType>>>
val types: List<PrivacyType>
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
index f7ca51d6f840..a6e48f8835c7 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
@@ -62,4 +62,6 @@ data class PrivacyApplication(val packageName: String, val uid: Int, val context
context.packageManager.getApplicationLabel(it) as String
} ?: packageName
}
+
+ override fun toString() = "PrivacyApplication(packageName=$packageName, uid=$uid)"
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index f1c3bf299eea..625eacd7e2a7 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -26,16 +26,26 @@ import android.os.Handler
import android.os.UserHandle
import android.os.UserManager
import com.android.internal.annotations.VisibleForTesting
-import com.android.systemui.Dependency
+import com.android.systemui.Dependency.BG_HANDLER_NAME
+import com.android.systemui.Dependency.MAIN_HANDLER_NAME
+import com.android.systemui.R
import com.android.systemui.appops.AppOpItem
import com.android.systemui.appops.AppOpsController
-import com.android.systemui.R
+import com.android.systemui.Dumpable
+import java.io.FileDescriptor
+import java.io.PrintWriter
import java.lang.ref.WeakReference
import javax.inject.Inject
+import javax.inject.Named
import javax.inject.Singleton
@Singleton
-class PrivacyItemController @Inject constructor(val context: Context) {
+class PrivacyItemController @Inject constructor(
+ val context: Context,
+ private val appOpsController: AppOpsController,
+ @Named(MAIN_HANDLER_NAME) private val uiHandler: Handler,
+ @Named(BG_HANDLER_NAME) private val bgHandler: Handler
+) : Dumpable {
companion object {
val OPS = intArrayOf(AppOpsManager.OP_CAMERA,
@@ -48,16 +58,13 @@ class PrivacyItemController @Inject constructor(val context: Context) {
const val TAG = "PrivacyItemController"
const val SYSTEM_UID = 1000
}
- private var privacyList = emptyList<PrivacyItem>()
- @Suppress("DEPRECATION")
- private val appOpsController = Dependency.get(AppOpsController::class.java)
+ @VisibleForTesting
+ internal var privacyList = emptyList<PrivacyItem>()
+ get() = field.toList() // Provides a shallow copy of the list
+
private val userManager = context.getSystemService(UserManager::class.java)
private var currentUserIds = emptyList<Int>()
- @Suppress("DEPRECATION")
- private val bgHandler = Handler(Dependency.get(Dependency.BG_LOOPER))
- @Suppress("DEPRECATION")
- private val uiHandler = Dependency.get(Dependency.MAIN_HANDLER)
private var listening = false
val systemApp =
PrivacyApplication(context.getString(R.string.device_services), SYSTEM_UID, context)
@@ -188,4 +195,22 @@ class PrivacyItemController @Inject constructor(val context: Context) {
callback?.privacyChanged(list)
}
}
+
+ override fun dump(fd: FileDescriptor?, pw: PrintWriter?, args: Array<out String>?) {
+ pw?.println("PrivacyItemController state:")
+ pw?.println(" Listening: $listening")
+ pw?.println(" Current user ids: $currentUserIds")
+ pw?.println(" Privacy Items:")
+ privacyList.forEach {
+ pw?.print(" ")
+ pw?.println(it.toString())
+ }
+ pw?.println(" Callbacks:")
+ callbacks.forEach {
+ it.get()?.let {
+ pw?.print(" ")
+ pw?.println(it.toString())
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index b865ce8d261a..f91c9d944439 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -189,6 +189,7 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight,
oldBottom) -> updateAnimator(right - left));
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+ updateEverything();
}
private void updateAnimator(int width) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 74e82b270aa0..c0f87cb37e50 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -48,7 +48,6 @@ import android.util.Pair;
import android.view.DisplayCutout;
import android.view.View;
import android.view.WindowInsets;
-import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -124,6 +123,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements
private TintedIconManager mIconManager;
private TouchAnimator mStatusIconsAlphaAnimator;
private TouchAnimator mHeaderTextContainerAlphaAnimator;
+ private TouchAnimator mPrivacyChipAlphaAnimator;
private View mSystemIconsView;
private View mQuickQsStatusIcons;
@@ -212,6 +212,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements
mNextAlarmTextView = findViewById(R.id.next_alarm_text);
mRingerModeIcon = findViewById(R.id.ringer_mode_icon);
mRingerModeTextView = findViewById(R.id.ringer_mode_text);
+ mPrivacyChip = findViewById(R.id.privacy_chip);
+ mPrivacyChip.setOnClickListener(this);
updateResources();
@@ -230,8 +232,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements
mClockView = findViewById(R.id.clock);
mClockView.setOnClickListener(this);
mDateView = findViewById(R.id.date);
- mPrivacyChip = findViewById(R.id.privacy_chip);
- mPrivacyChip.setOnClickListener(this);
mSpace = findViewById(R.id.space);
// Tint for the battery icons are handled in setupHost()
@@ -383,6 +383,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements
updateStatusIconAlphaAnimator();
updateHeaderTextContainerAlphaAnimator();
+ updatePrivacyChipAlphaAnimator();
}
private void updateStatusIconAlphaAnimator() {
@@ -398,6 +399,12 @@ public class QuickStatusBarHeader extends RelativeLayout implements
.build();
}
+ private void updatePrivacyChipAlphaAnimator() {
+ mPrivacyChipAlphaAnimator = new TouchAnimator.Builder()
+ .addFloat(mPrivacyChip, "alpha", 1, 0, 1)
+ .build();
+ }
+
public void setExpanded(boolean expanded) {
if (mExpanded == expanded) return;
mExpanded = expanded;
@@ -431,6 +438,10 @@ public class QuickStatusBarHeader extends RelativeLayout implements
if (mHeaderTextContainerAlphaAnimator != null) {
mHeaderTextContainerAlphaAnimator.setPosition(keyguardExpansionFraction);
}
+ if (mPrivacyChipAlphaAnimator != null) {
+ mPrivacyChip.setExpanded(expansionFraction > 0.5);
+ mPrivacyChipAlphaAnimator.setPosition(keyguardExpansionFraction);
+ }
// Check the original expansion fraction - we don't want to show the tooltip until the
// panel is pulled all the way out.
@@ -541,12 +552,10 @@ public class QuickStatusBarHeader extends RelativeLayout implements
Handler mUiHandler = new Handler(Looper.getMainLooper());
mUiHandler.post(() -> {
Dialog mDialog = new OngoingPrivacyDialog(mContext, builder).createDialog();
- mDialog.getWindow().setType(
- WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- SystemUIDialog.setShowForAllUsers(mDialog, true);
+ SystemUIDialog.setShowForAllUsers(mDialog, false);
SystemUIDialog.registerDismissListener(mDialog);
SystemUIDialog.setWindowOnTop(mDialog);
- mUiHandler.post(() -> mDialog.show());
+ mActivityStarter.postQSRunnableDismissingKeyguard(() -> mDialog.show());
mHost.collapsePanels();
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index c474faf6b1e0..83c4cfc6c126 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -24,6 +24,10 @@ import static android.view.MotionEvent.ACTION_UP;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_CHANNEL;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -32,7 +36,9 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.graphics.Rect;
+import android.graphics.Region;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -41,6 +47,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
+import android.view.InputChannel;
import android.view.MotionEvent;
import com.android.internal.policy.ScreenDecorationsUtils;
@@ -51,6 +58,7 @@ import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.InputChannelCompat.InputEventDispatcher;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.CallbackController;
@@ -93,6 +101,8 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
private final Intent mQuickStepIntent;
+ private Region mActiveNavBarRegion;
+
private IOverviewProxy mOverviewProxy;
private int mConnectionBackoffAttempts;
private @InteractionType int mInteractionFlags;
@@ -103,6 +113,8 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
private float mWindowCornerRadius;
private boolean mSupportsRoundedCornersOnWindows;
+ private InputEventDispatcher mInputEventDispatcher;
+
private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
public void startScreenPinning(int taskId) {
@@ -309,6 +321,20 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
mCurrentBoundedUserId = -1;
Log.e(TAG_OPS, "Failed to call onBind()", e);
}
+
+ Bundle params = new Bundle();
+ params.putBinder(KEY_EXTRA_SYSUI_PROXY, mSysUiProxy.asBinder());
+ params.putParcelable(KEY_EXTRA_INPUT_CHANNEL, createNewInputDispatcher());
+ params.putFloat(KEY_EXTRA_WINDOW_CORNER_RADIUS, mWindowCornerRadius);
+ params.putBoolean(KEY_EXTRA_SUPPORTS_WINDOW_CORNERS, mSupportsRoundedCornersOnWindows);
+ try {
+ mOverviewProxy.onInitialize(params);
+ } catch (RemoteException e) {
+ // Ignore error until the migration is complete.
+ Log.e(TAG_OPS, "Failed to call onBind()", e);
+ }
+ dispatchNavButtonBounds();
+
notifyConnectionChanged();
}
@@ -317,6 +343,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
Log.w(TAG_OPS, "Null binding of '" + name + "', try reconnecting");
mCurrentBoundedUserId = -1;
retryConnectionWithBackoff();
+ disposeInputDispatcher();
}
@Override
@@ -324,15 +351,32 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
Log.w(TAG_OPS, "Binding died of '" + name + "', try reconnecting");
mCurrentBoundedUserId = -1;
retryConnectionWithBackoff();
+ disposeInputDispatcher();
}
@Override
public void onServiceDisconnected(ComponentName name) {
// Do nothing
mCurrentBoundedUserId = -1;
+ disposeInputDispatcher();
}
};
+ private void disposeInputDispatcher() {
+ if (mInputEventDispatcher != null) {
+ mInputEventDispatcher.dispose();
+ mInputEventDispatcher = null;
+ }
+ }
+
+ private InputChannel createNewInputDispatcher() {
+ disposeInputDispatcher();
+
+ InputChannel[] channels = InputChannel.openInputChannelPair("overview-proxy-service");
+ mInputEventDispatcher = new InputEventDispatcher(channels[0], Looper.getMainLooper());
+ return channels[1];
+ }
+
private final DeviceProvisionedListener mDeviceProvisionedCallback =
new DeviceProvisionedListener() {
@Override
@@ -382,6 +426,24 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
}
}
+ /**
+ * Sets the navbar region which can receive touch inputs
+ */
+ public void onActiveNavBarRegionChanges(Region activeRegion) {
+ mActiveNavBarRegion = activeRegion;
+ dispatchNavButtonBounds();
+ }
+
+ private void dispatchNavButtonBounds() {
+ if (mOverviewProxy != null && mActiveNavBarRegion != null) {
+ try {
+ mOverviewProxy.onActiveNavBarRegionChanges(mActiveNavBarRegion);
+ } catch (RemoteException e) {
+ Log.e(TAG_OPS, "Failed to call onActiveNavBarRegionChanges()", e);
+ }
+ }
+ }
+
public float getBackButtonAlpha() {
return mBackButtonAlpha;
}
@@ -477,6 +539,10 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
return mOverviewProxy;
}
+ public InputEventDispatcher getInputEventDispatcher() {
+ return mInputEventDispatcher;
+ }
+
public int getInteractionFlags() {
return mInteractionFlags;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index be749aef7f25..164f5826061e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -424,22 +424,28 @@ public class KeyguardIndicationController implements StateListener {
final boolean hasChargingTime = chargingTimeRemaining > 0;
int chargingId;
- switch (mChargingSpeed) {
- case KeyguardUpdateMonitor.BatteryStatus.CHARGING_FAST:
- chargingId = hasChargingTime
- ? R.string.keyguard_indication_charging_time_fast
- : R.string.keyguard_plugged_in_charging_fast;
- break;
- case KeyguardUpdateMonitor.BatteryStatus.CHARGING_SLOWLY:
- chargingId = hasChargingTime
- ? R.string.keyguard_indication_charging_time_slowly
- : R.string.keyguard_plugged_in_charging_slowly;
- break;
- default:
- chargingId = hasChargingTime
- ? R.string.keyguard_indication_charging_time
- : R.string.keyguard_plugged_in;
- break;
+ if (mPowerPluggedInWired) {
+ switch (mChargingSpeed) {
+ case KeyguardUpdateMonitor.BatteryStatus.CHARGING_FAST:
+ chargingId = hasChargingTime
+ ? R.string.keyguard_indication_charging_time_fast
+ : R.string.keyguard_plugged_in_charging_fast;
+ break;
+ case KeyguardUpdateMonitor.BatteryStatus.CHARGING_SLOWLY:
+ chargingId = hasChargingTime
+ ? R.string.keyguard_indication_charging_time_slowly
+ : R.string.keyguard_plugged_in_charging_slowly;
+ break;
+ default:
+ chargingId = hasChargingTime
+ ? R.string.keyguard_indication_charging_time
+ : R.string.keyguard_plugged_in;
+ break;
+ }
+ } else {
+ chargingId = hasChargingTime
+ ? R.string.keyguard_indication_charging_time_wireless
+ : R.string.keyguard_plugged_in_wireless;
}
String percentage = NumberFormat.getPercentInstance()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
index e11ec2d24e29..2edea789d820 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -158,18 +158,6 @@ public class NavigationBarController implements DisplayListener, Callbacks {
});
}
- /** Removes navigation bars. */
- public void destroy() {
- mDisplayManager.unregisterDisplayListener(this);
- if (mNavigationBars.size() > 0) {
- for (int i = 0; i < mNavigationBars.size(); i++) {
- int displayId = mNavigationBars.keyAt(i);
- removeNavigationBar(displayId);
- }
- mNavigationBars.clear();
- }
- }
-
private void removeNavigationBar(int displayId) {
NavigationBarFragment navBar = mNavigationBars.get(displayId);
if (navBar != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index c25b7cfd804c..1cc6dc391c1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -42,8 +42,6 @@ public interface NotificationLockscreenUserManager {
/** Adds a listener to be notified when the current user changes. */
void addUserChangedListener(UserChangedListener listener);
- void destroy();
-
SparseArray<UserInfo> getCurrentProfiles();
void setLockscreenPublicMode(boolean isProfilePublic, int userId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 6a49b804f5ba..9cb6f11fb558 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -550,12 +550,6 @@ public class NotificationLockscreenUserManagerImpl implements
return mKeyguardMonitor.isSecure() || mLockPatternUtils.isSecure(userId);
}
- public void destroy() {
- mContext.unregisterReceiver(mBaseBroadcastReceiver);
- mContext.unregisterReceiver(mAllUsersReceiver);
- mListeners.clear();
- }
-
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("NotificationLockscreenUserManager state:");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 01b0bb14c7ca..110d51563e2c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -348,15 +348,13 @@ public class NotificationShelf extends ActivatableNotificationView implements
if (notGoneIndex == 0) {
StatusBarIconView icon = row.getEntry().expandedIcon;
NotificationIconContainer.IconState iconState = getIconState(icon);
+ // The icon state might be null in rare cases where the notification is actually
+ // added to the layout, but not to the shelf. An example are replied messages, since
+ // they don't show up on AOD
if (iconState != null && iconState.clampedAppearAmount == 1.0f) {
// only if the first icon is fully in the shelf we want to clip to it!
backgroundTop = (int) (row.getTranslationY() - getTranslationY());
firstElementRoundness = row.getCurrentTopRoundness();
- } else if (iconState == null) {
- Log.wtf(TAG, "iconState is null. ExpandedIcon: " + row.getEntry().expandedIcon
- + (row.getEntry().expandedIcon != null
- ? "\n icon parent: " + row.getEntry().expandedIcon.getParent() : "")
- + " \n number of notifications: " + mHostLayout.getChildCount() );
}
}
if (row.isFirstInSection() && previousRow != null && previousRow.isLastInSection()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 662cf514b977..ee5ac7c602aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -24,6 +24,7 @@ import android.view.View;
import android.view.ViewGroup;
import com.android.systemui.R;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -61,7 +62,7 @@ public class NotificationViewHierarchyManager {
protected final NotificationLockscreenUserManager mLockscreenUserManager;
protected final NotificationGroupManager mGroupManager;
protected final VisualStabilityManager mVisualStabilityManager;
- private final StatusBarStateControllerImpl mStatusBarStateController;
+ private final SysuiStatusBarStateController mStatusBarStateController;
private final NotificationEntryManager mEntryManager;
// Lazy
@@ -82,13 +83,13 @@ public class NotificationViewHierarchyManager {
NotificationLockscreenUserManager notificationLockscreenUserManager,
NotificationGroupManager groupManager,
VisualStabilityManager visualStabilityManager,
- StatusBarStateControllerImpl statusBarStateController,
+ StatusBarStateController statusBarStateController,
NotificationEntryManager notificationEntryManager,
Lazy<ShadeController> shadeController) {
mLockscreenUserManager = notificationLockscreenUserManager;
mGroupManager = groupManager;
mVisualStabilityManager = visualStabilityManager;
- mStatusBarStateController = statusBarStateController;
+ mStatusBarStateController = (SysuiStatusBarStateController) statusBarStateController;
mEntryManager = notificationEntryManager;
mShadeController = shadeController;
Resources res = context.getResources();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
index 839b06cec496..1ed671fdb6fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
@@ -47,7 +47,11 @@ public interface NotificationEntryListener {
}
/**
- * Called when a notification is updated, before any filtering of notifications have occurred.
+ * Called when a notification is about to be updated. Notification- and ranking-derived fields
+ * on the entry have already been updated but the following have not yet occurred:
+ * (a) View binding (i.e. the associated view has not yet been updated / inflation has not yet
+ * been kicked off.
+ * (b) Notification filtering
*/
default void onPreEntryUpdated(NotificationEntry entry) {
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 81d0e25782db..56922be73bec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -230,7 +230,6 @@ public class NotificationEntryManager implements
}
}
}
- entry.setLowPriorityStateUpdated(false);
}
@Override
@@ -346,8 +345,7 @@ public class NotificationEntryManager implements
Dependency.get(LeakDetector.class).trackInstance(entry);
// Construct the expanded view.
- getRowBinder().inflateViews(entry, () -> performRemoveNotification(notification),
- mNotificationData.get(entry.key) != null);
+ getRowBinder().inflateViews(entry, () -> performRemoveNotification(notification));
abortExistingInflation(key);
@@ -384,13 +382,11 @@ public class NotificationEntryManager implements
mNotificationData.update(entry, ranking, notification);
- getRowBinder().inflateViews(entry, () -> performRemoveNotification(notification),
- mNotificationData.get(entry.key) != null);
-
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onPreEntryUpdated(entry);
}
+ getRowBinder().inflateViews(entry, () -> performRemoveNotification(notification));
updateNotifications();
if (DEBUG) {
@@ -422,6 +418,7 @@ public class NotificationEntryManager implements
}
}
+ @Override
public void updateNotificationRanking(NotificationListenerService.RankingMap rankingMap) {
List<NotificationEntry> entries = new ArrayList<>();
entries.addAll(mNotificationData.getActiveNotifications());
@@ -447,8 +444,7 @@ public class NotificationEntryManager implements
entry,
oldImportances.get(entry.key),
oldAdjustments.get(entry.key),
- NotificationUiAdjustment.extractFromNotificationEntry(entry),
- mNotificationData.get(entry.key) != null);
+ NotificationUiAdjustment.extractFromNotificationEntry(entry));
}
updateNotifications();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
index 88f4ca239af4..769cbb7b984c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
@@ -61,11 +61,6 @@ public class NotificationListController {
mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
}
- /** Should be called when the list controller is being destroyed. */
- public void destroy() {
- mDeviceProvisionedController.removeCallback(mDeviceProvisionedListener);
- }
-
@SuppressWarnings("FieldCanBeLocal")
private final NotificationEntryListener mEntryListener = new NotificationEntryListener() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
index 0b8596f9cba7..f1bb0d77deaa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
@@ -124,8 +124,7 @@ public class NotificationRowBinder {
*/
public void inflateViews(
NotificationEntry entry,
- Runnable onDismissRunnable,
- boolean isUpdate)
+ Runnable onDismissRunnable)
throws InflationException {
ViewGroup parent = mListContainer.getViewParentForNotification(entry);
PackageManager pmUser = StatusBar.getPackageManagerForUser(mContext,
@@ -135,13 +134,13 @@ public class NotificationRowBinder {
if (entry.rowExists()) {
entry.updateIcons(mContext, sbn);
entry.reset();
- updateNotification(entry, pmUser, sbn, entry.getRow(), isUpdate);
+ updateNotification(entry, pmUser, sbn, entry.getRow());
} else {
entry.createIcons(mContext, sbn);
new RowInflaterTask().inflate(mContext, parent, entry,
row -> {
bindRow(entry, pmUser, sbn, row, onDismissRunnable);
- updateNotification(entry, pmUser, sbn, row, isUpdate);
+ updateNotification(entry, pmUser, sbn, row);
});
}
}
@@ -197,15 +196,14 @@ public class NotificationRowBinder {
NotificationEntry entry,
@Nullable Integer oldImportance,
NotificationUiAdjustment oldAdjustment,
- NotificationUiAdjustment newAdjustment,
- boolean isUpdate) {
+ NotificationUiAdjustment newAdjustment) {
if (NotificationUiAdjustment.needReinflate(oldAdjustment, newAdjustment)) {
if (entry.rowExists()) {
entry.reset();
PackageManager pmUser = StatusBar.getPackageManagerForUser(
mContext,
entry.notification.getUser().getIdentifier());
- updateNotification(entry, pmUser, entry.notification, entry.getRow(), isUpdate);
+ updateNotification(entry, pmUser, entry.notification, entry.getRow());
} else {
// Once the RowInflaterTask is done, it will pick up the updated entry, so
// no-op here.
@@ -224,12 +222,8 @@ public class NotificationRowBinder {
NotificationEntry entry,
PackageManager pmUser,
StatusBarNotification sbn,
- ExpandableNotificationRow row,
- boolean isUpdate) {
- boolean isLowPriority = entry.ambient;
- boolean wasLowPriority = row.isLowPriority();
- row.setIsLowPriority(isLowPriority);
- row.setLowPriorityStateUpdated(isUpdate && (wasLowPriority != isLowPriority));
+ ExpandableNotificationRow row) {
+ row.setIsLowPriority(entry.ambient);
// bind the click event to the content area
checkNotNull(mNotificationClicker).register(row, sbn);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
index c886685424f7..396a3a7834fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
@@ -45,7 +45,7 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener {
private boolean mReorderingAllowed;
private VisibilityLocationProvider mVisibilityLocationProvider;
private ArraySet<View> mAllowedReorderViews = new ArraySet<>();
- private ArraySet<View> mLowPriorityReorderingViews = new ArraySet<>();
+ private ArraySet<NotificationEntry> mLowPriorityReorderingViews = new ArraySet<>();
private ArraySet<View> mAddedChildren = new ArraySet<>();
private boolean mPulsing;
@@ -53,14 +53,21 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener {
public VisualStabilityManager(NotificationEntryManager notificationEntryManager) {
notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
- public void onEntryReinflated(NotificationEntry entry) {
- if (entry.hasLowPriorityStateUpdated()) {
- onLowPriorityUpdated(entry);
- if (mPresenter != null) {
- mPresenter.updateNotificationViews();
- }
+ public void onPreEntryUpdated(NotificationEntry entry) {
+ final boolean mAmbientStateHasChanged =
+ entry.ambient != entry.getRow().isLowPriority();
+ if (mAmbientStateHasChanged) {
+ mLowPriorityReorderingViews.add(entry);
}
}
+
+ @Override
+ public void onPostEntryUpdated(NotificationEntry entry) {
+ // This line is technically not required as we'll get called as the hierarchy
+ // manager will call onReorderingFinished() immediately before this.
+ // TODO: Find a way to make this relationship more explicit
+ mLowPriorityReorderingViews.remove(entry);
+ }
});
}
@@ -142,7 +149,7 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener {
if (mAddedChildren.contains(row)) {
return true;
}
- if (mLowPriorityReorderingViews.contains(row)) {
+ if (mLowPriorityReorderingViews.contains(row.getEntry())) {
return true;
}
if (mAllowedReorderViews.contains(row)
@@ -172,10 +179,6 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener {
}
}
- private void onLowPriorityUpdated(NotificationEntry entry) {
- mLowPriorityReorderingViews.add(entry.getRow());
- }
-
/**
* Notify the visual stability manager that a new view was added and should be allowed to
* reorder next time.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
index 54ed0d9cd8ce..8b522a2033f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
@@ -16,8 +16,10 @@
package com.android.systemui.statusbar.notification.collection;
+import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
+import android.app.Person;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.SnoozeCriterion;
@@ -235,8 +237,11 @@ public class NotificationData {
if (mRankingMap != null) {
getRanking(statusBarNotification.getKey(), mTmpRanking);
if (mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT
- || statusBarNotification.getNotification().isForegroundService()
- || statusBarNotification.getNotification().hasMediaSession()) {
+ || isImportantOngoing(statusBarNotification.getNotification())
+ || statusBarNotification.getNotification().hasMediaSession()
+ || hasPerson(statusBarNotification.getNotification())
+ || hasStyle(statusBarNotification.getNotification(),
+ Notification.MessagingStyle.class)) {
return true;
}
if (mGroupManager.isSummaryOfGroup(statusBarNotification)) {
@@ -252,6 +257,24 @@ public class NotificationData {
return false;
}
+ private boolean isImportantOngoing(Notification notification) {
+ return notification.isForegroundService()
+ && mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_LOW;
+ }
+
+ private boolean hasStyle(Notification notification, Class targetStyle) {
+ Class<? extends Notification.Style> style = notification.getNotificationStyle();
+ return targetStyle.equals(style);
+ }
+
+ private boolean hasPerson(Notification notification) {
+ // TODO: cache favorite and recent contacts to check contact affinity
+ ArrayList<Person> people = notification.extras != null
+ ? notification.extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST)
+ : new ArrayList<>();
+ return people != null && !people.isEmpty();
+ }
+
public boolean isAmbient(String key) {
if (mRankingMap != null) {
getRanking(key, mTmpRanking);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index f74de5beb585..f6d4ce22e905 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -622,10 +622,6 @@ public final class NotificationEntry {
return null;
}
- public boolean hasLowPriorityStateUpdated() {
- return row != null && row.hasLowPriorityStateUpdated();
- }
-
public void removeRow() {
if (row != null) row.setRemoved();
}
@@ -650,10 +646,6 @@ public final class NotificationEntry {
return parent == null;
}
- public void setLowPriorityStateUpdated(boolean updated) {
- if (row != null) row.setLowPriorityStateUpdated(updated);
- }
-
/**
* @return Can the underlying notification be cleared? This can be different from whether the
* notification can be dismissed in case notifications are sensitive on the lockscreen.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java
index 43b5503682cc..a1fcbebecea1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java
@@ -30,6 +30,9 @@ public class NotificationCounters {
/** Counter tag for when the user hits 'stop notifications' in the blocking helper. */
public static final String BLOCKING_HELPER_STOP_NOTIFICATIONS =
"blocking_helper_stop_notifications";
+ /** Counter tag for when the user hits 'deliver silently' in the blocking helper. */
+ public static final String BLOCKING_HELPER_DELIVER_SILENTLY =
+ "blocking_helper_deliver_silently";
/** Counter tag for when the user hits 'show silently' in the blocking helper. */
public static final String BLOCKING_HELPER_TOGGLE_SILENT =
"blocking_helper_toggle_silent";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index b8e33a8e0d2d..69828c166463 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -124,6 +124,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
public static final float DEFAULT_HEADER_VISIBLE_AMOUNT = 1.0f;
private static final long RECENTLY_ALERTED_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(30);
private boolean mUpdateBackgroundOnUpdate;
+ private boolean mNotificationTranslationFinished = false;
/**
* Listener for when {@link ExpandableNotificationRow} is laid out.
@@ -133,7 +134,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
private LayoutListener mLayoutListener;
- private boolean mLowPriorityStateUpdated;
private final NotificationInflater mNotificationInflater;
private int mIconTransformContentShift;
private int mIconTransformContentShiftNoIcon;
@@ -1213,6 +1213,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
l.initView();
l.reInflateViews();
}
+ mStatusBarNotification.clearPackageContext();
mNotificationInflater.clearCachesAndReInflate();
onNotificationUpdated();
}
@@ -1453,6 +1454,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return mIsBlockingHelperShowing;
}
+ public boolean isBlockingHelperShowingAndTranslationFinished() {
+ return mIsBlockingHelperShowing && mNotificationTranslationFinished;
+ }
+
public void setOnDismissRunnable(Runnable onDismissRunnable) {
mOnDismissRunnable = onDismissRunnable;
}
@@ -1577,15 +1582,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
-
- public void setLowPriorityStateUpdated(boolean lowPriorityStateUpdated) {
- mLowPriorityStateUpdated = lowPriorityStateUpdated;
- }
-
- public boolean hasLowPriorityStateUpdated() {
- return mLowPriorityStateUpdated;
- }
-
public boolean isLowPriority() {
return mIsLowPriority;
}
@@ -1851,7 +1847,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
void onGutsOpened() {
- resetTranslation();
updateContentAccessibilityImportanceForGuts(false /* isEnabled */);
}
@@ -1905,11 +1900,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
@Override
public void setTranslation(float translationX) {
- if (areGutsExposed()) {
- // Don't translate if guts are showing.
+ if (isBlockingHelperShowingAndTranslationFinished()) {
+ mGuts.setTranslationX(translationX);
return;
- }
- if (!mShouldTranslateContents) {
+ } else if (!mShouldTranslateContents) {
setTranslationX(translationX);
} else if (mTranslateableViews != null) {
// Translate the group of views
@@ -1925,6 +1919,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
// positioning, so we can use the scrollX instead.
getEntry().expandedIcon.setScrollX((int) -translationX);
}
+
if (mMenuRow.getMenuView() != null) {
mMenuRow.onParentTranslationUpdate(translationX);
}
@@ -1936,6 +1931,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return getTranslationX();
}
+ if (isBlockingHelperShowingAndCanTranslate()) {
+ return mGuts.getTranslationX();
+ }
+
if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
// All of the views in the list should have same translation, just use first one.
return mTranslateableViews.get(0).getTranslationX();
@@ -1944,15 +1943,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return 0;
}
+ private boolean isBlockingHelperShowingAndCanTranslate() {
+ return areGutsExposed() && mIsBlockingHelperShowing && mNotificationTranslationFinished;
+ }
+
public Animator getTranslateViewAnimator(final float leftTarget,
AnimatorUpdateListener listener) {
if (mTranslateAnim != null) {
mTranslateAnim.cancel();
}
- if (areGutsExposed()) {
- // No translation if guts are exposed.
- return null;
- }
+
final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
leftTarget);
if (listener != null) {
@@ -1968,6 +1968,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
@Override
public void onAnimationEnd(Animator anim) {
+ if (mIsBlockingHelperShowing) {
+ mNotificationTranslationFinished = true;
+ }
if (!cancelled && leftTarget == 0) {
mMenuRow.resetMenu();
mTranslateAnim = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 80956159c20b..1dc48d4b18b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -68,6 +68,7 @@ import java.util.List;
public class NotificationContentView extends FrameLayout {
private static final String TAG = "NotificationContentView";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final int VISIBLE_TYPE_CONTRACTED = 0;
public static final int VISIBLE_TYPE_EXPANDED = 1;
public static final int VISIBLE_TYPE_HEADSUP = 2;
@@ -1319,6 +1320,14 @@ public class NotificationContentView extends FrameLayout {
SmartRepliesAndActions smartRepliesAndActions =
chooseSmartRepliesAndActions(mSmartReplyConstants, entry);
+ if (DEBUG) {
+ Log.d(TAG, String.format("Adding suggestions for %s, %d actions, and %d replies.",
+ entry.notification.getKey(),
+ smartRepliesAndActions.smartActions == null ? 0 :
+ smartRepliesAndActions.smartActions.actions.size(),
+ smartRepliesAndActions.smartReplies == null ? 0 :
+ smartRepliesAndActions.smartReplies.choices.length));
+ }
applyRemoteInput(entry, smartRepliesAndActions.hasFreeformRemoteInput);
applySmartReplyView(smartRepliesAndActions, entry);
@@ -1341,6 +1350,10 @@ public class NotificationContentView extends FrameLayout {
notification.findRemoteInputActionPair(true /* freeform */);
if (!smartReplyConstants.isEnabled()) {
+ if (DEBUG) {
+ Log.d(TAG, "Smart suggestions not enabled, not adding suggestions for "
+ + entry.notification.getKey());
+ }
return new SmartRepliesAndActions(null, null, freeformRemoteInputActionPair != null);
}
// Only use smart replies from the app if they target P or above. We have this check because
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index c7b2fab54fff..37237317fc95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -84,6 +84,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
public static final int ACTION_UNDO = 1;
public static final int ACTION_TOGGLE_SILENT = 2;
public static final int ACTION_BLOCK = 3;
+ public static final int ACTION_DELIVER_SILENTLY = 4;
private INotificationManager mINotificationManager;
private PackageManager mPm;
@@ -135,30 +136,26 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
};
private OnClickListener mOnToggleSilent = v -> {
- Runnable saveImportance = () -> {
- swapContent(ACTION_TOGGLE_SILENT, true /* animate */);
- if (mIsForBlockingHelper) {
- mMetricsLogger.write(getLogMaker()
- .setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
- .setType(MetricsEvent.TYPE_ACTION)
- .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_ALERT_ME));
- }
- };
- if (mCheckSaveListener != null) {
- mCheckSaveListener.checkSave(saveImportance, mSbn);
- } else {
- saveImportance.run();
- }
+ handleSaveImportance(ACTION_TOGGLE_SILENT, MetricsEvent.BLOCKING_HELPER_CLICK_ALERT_ME);
+ };
+
+ private OnClickListener mOnDeliverSilently = v -> {
+ handleSaveImportance(
+ ACTION_DELIVER_SILENTLY, MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT);
};
private OnClickListener mOnStopOrMinimizeNotifications = v -> {
+ handleSaveImportance(ACTION_BLOCK, MetricsEvent.BLOCKING_HELPER_CLICK_BLOCKED);
+ };
+
+ private void handleSaveImportance(int action, int metricsSubtype) {
Runnable saveImportance = () -> {
- swapContent(ACTION_BLOCK, true /* animate */);
+ swapContent(action, true /* animate */);
if (mIsForBlockingHelper) {
mMetricsLogger.write(getLogMaker()
.setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
.setType(MetricsEvent.TYPE_ACTION)
- .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_BLOCKED));
+ .setSubtype(metricsSubtype));
}
};
if (mCheckSaveListener != null) {
@@ -166,7 +163,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
} else {
saveImportance.run();
}
- };
+ }
private OnClickListener mOnUndo = v -> {
// Reset exit counter that we'll log and record an undo event separately (not an exit event)
@@ -283,8 +280,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
mMetricsLogger.write(notificationControlsLogMaker());
}
-
-
private void bindHeader() throws RemoteException {
// Package name
Drawable pkgicon = null;
@@ -479,17 +474,21 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
findViewById(R.id.block_or_minimize).setVisibility(VISIBLE);
findViewById(R.id.interruptiveness_settings).setVisibility(GONE);
View block = findViewById(R.id.block);
- TextView keep = findViewById(R.id.keep);
+ TextView done = findViewById(R.id.done);
View minimize = findViewById(R.id.minimize);
+ View deliverSilently = findViewById(R.id.deliver_silently);
+
block.setOnClickListener(mOnStopOrMinimizeNotifications);
- keep.setOnClickListener(mOnKeepShowing);
+ done.setOnClickListener(mOnKeepShowing);
minimize.setOnClickListener(mOnStopOrMinimizeNotifications);
+ deliverSilently.setOnClickListener(mOnDeliverSilently);
if (mIsNonblockable) {
- keep.setText(android.R.string.ok);
+ done.setText(android.R.string.ok);
block.setVisibility(GONE);
minimize.setVisibility(GONE);
+ deliverSilently.setVisibility(GONE);
} else if (mIsForeground) {
block.setVisibility(GONE);
minimize.setVisibility(VISIBLE);
@@ -499,7 +498,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
// Set up app settings link (i.e. Customize)
- TextView settingsLinkView = findViewById(R.id.app_settings);
+ View settingsLinkView = findViewById(R.id.app_settings);
Intent settingsIntent = getAppSettingsIntent(mPm, mPackageName,
mSingleNotificationChannel,
mSbn.getId(), mSbn.getTag());
@@ -507,7 +506,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
&& settingsIntent != null
&& !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) {
settingsLinkView.setVisibility(VISIBLE);
- settingsLinkView.setText(mContext.getString(R.string.notification_app_settings));
settingsLinkView.setOnClickListener((View view) -> {
mAppSettingsClickListener.onClick(view, settingsIntent);
});
@@ -531,6 +529,11 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
case ACTION_UNDO:
mChosenImportance = mStartingChannelImportance;
break;
+ case ACTION_DELIVER_SILENTLY:
+ mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
+ mChosenImportance = IMPORTANCE_LOW;
+ confirmationText.setText(R.string.notification_channel_silenced);
+ break;
case ACTION_TOGGLE_SILENT:
mExitReason = NotificationCounters.BLOCKING_HELPER_TOGGLE_SILENT;
if (mWasShownHighPriority) {
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 7105876907bf..fbf1e310abf2 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
@@ -578,6 +578,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@Override
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onDensityOrFontScaleChanged() {
+ reinflateViews();
+ }
+
+ private void reinflateViews() {
inflateFooterView();
inflateEmptyShadeView();
updateFooter();
@@ -608,6 +612,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mCornerRadius = newRadius;
invalidate();
}
+ reinflateViews();
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 2a8808021715..7882fd32e044 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -195,6 +195,9 @@ public class StackScrollAlgorithm {
return false;
}
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
+ if (row.isBlockingHelperShowingAndTranslationFinished()) {
+ return true;
+ }
if (row.areGutsExposed() || !row.getEntry().hasFinishedInitialization()) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 4c1c0a4b4e58..de0e194ef90c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -141,10 +141,6 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
mAnimationStateHandler = handler;
}
- public void destroy() {
- Dependency.get(StatusBarStateController.class).removeCallback(this);
- }
-
private void initResources() {
Resources resources = mContext.getResources();
mStatusBarHeight = resources.getDimensionPixelSize(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 651670cbf2c0..ebd420478c0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -45,6 +45,8 @@ import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.Region;
+import android.graphics.Region.Op;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -128,8 +130,8 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
private Rect mBackButtonBounds = new Rect();
private Rect mRecentsButtonBounds = new Rect();
private Rect mRotationButtonBounds = new Rect();
+ private final Region mActiveRegion = new Region();
private int[] mTmpPosition = new int[2];
- private Rect mTmpRect = new Rect();
private KeyButtonDrawable mBackIcon;
private KeyButtonDrawable mHomeDefaultIcon;
@@ -954,17 +956,22 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- updateButtonLocationOnScreen(getBackButton(), mBackButtonBounds);
- updateButtonLocationOnScreen(getHomeButton(), mHomeButtonBounds);
- updateButtonLocationOnScreen(getRecentsButton(), mRecentsButtonBounds);
- updateButtonLocationOnScreen(getRotateSuggestionButton(), mRotationButtonBounds);
+
+ mActiveRegion.setEmpty();
+ updateButtonLocation(getBackButton(), mBackButtonBounds, true);
+ updateButtonLocation(getHomeButton(), mHomeButtonBounds, false);
+ updateButtonLocation(getRecentsButton(), mRecentsButtonBounds, false);
+ updateButtonLocation(getRotateSuggestionButton(), mRotationButtonBounds, true);
+ // TODO: Handle button visibility changes
+ mOverviewProxyService.onActiveNavBarRegionChanges(mActiveRegion);
if (mGestureHelper != null) {
mGestureHelper.onLayout(changed, left, top, right, bottom);
}
mRecentsOnboarding.setNavBarHeight(getMeasuredHeight());
}
- private void updateButtonLocationOnScreen(ButtonDispatcher button, Rect buttonBounds) {
+ private void updateButtonLocation(ButtonDispatcher button, Rect buttonBounds,
+ boolean isActive) {
View view = button.getCurrentView();
if (view == null) {
buttonBounds.setEmpty();
@@ -975,6 +982,14 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
final float posY = view.getTranslationY();
view.setTranslationX(0);
view.setTranslationY(0);
+
+ if (isActive) {
+ view.getLocationOnScreen(mTmpPosition);
+ buttonBounds.set(mTmpPosition[0], mTmpPosition[1],
+ mTmpPosition[0] + view.getMeasuredWidth(),
+ mTmpPosition[1] + view.getMeasuredHeight());
+ mActiveRegion.op(buttonBounds, Op.UNION);
+ }
view.getLocationInWindow(mTmpPosition);
buttonBounds.set(mTmpPosition[0], mTmpPosition[1],
mTmpPosition[0] + view.getMeasuredWidth(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 069703e9dd81..f4fa1e8246e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -590,11 +590,6 @@ public class NotificationPanelView extends PanelView implements
mClockPositionResult.clockX, CLOCK_ANIMATION_PROPERTIES, animateClock);
PropertyAnimator.setProperty(mKeyguardStatusView, AnimatableProperty.Y,
mClockPositionResult.clockY, CLOCK_ANIMATION_PROPERTIES, animateClock);
- // Move big clock up while pulling up the bouncer
- PropertyAnimator.setProperty(mBigClockContainer, AnimatableProperty.Y,
- MathUtils.lerp(-mBigClockContainer.getHeight(), 0,
- Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(getExpandedFraction())),
- CLOCK_ANIMATION_PROPERTIES, animateClock);
updateClock();
stackScrollerPadding = mClockPositionResult.stackScrollerPadding;
}
@@ -1334,8 +1329,7 @@ public class NotificationPanelView extends PanelView implements
}
};
- private void setKeyguardBottomAreaVisibility(int statusBarState,
- boolean goingToFullShade) {
+ private void setKeyguardBottomAreaVisibility(int statusBarState, boolean goingToFullShade) {
mKeyguardBottomArea.animate().cancel();
if (goingToFullShade) {
mKeyguardBottomArea.animate()
@@ -1438,6 +1432,7 @@ public class NotificationPanelView extends PanelView implements
if (mBarState == StatusBarState.SHADE_LOCKED
|| mBarState == StatusBarState.KEYGUARD) {
updateKeyguardBottomAreaAlpha();
+ updateBigClockAlpha();
}
if (mBarState == StatusBarState.SHADE && mQsExpanded
&& !mStackScrollerOverscrolling && mQsScrimEnabled) {
@@ -1883,6 +1878,19 @@ public class NotificationPanelView extends PanelView implements
}
}
+ /**
+ * Custom clock fades away when user drags up to unlock or pulls down quick settings.
+ *
+ * Updates alpha of custom clock to match the alpha of the KeyguardBottomArea. See
+ * {@link updateKeyguardBottomAreaAlpha}.
+ */
+ private void updateBigClockAlpha() {
+ float expansionAlpha = MathUtils.map(isUnlockHintRunning()
+ ? 0 : KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1f, 0f, 1f, getExpandedFraction());
+ float alpha = Math.min(expansionAlpha, 1 - getQsExpansionFraction());
+ mBigClockContainer.setAlpha(alpha);
+ }
+
private float getNotificationsTopY() {
if (mNotificationStackScroller.getNotGoneChildCount() == 0) {
return getExpandedHeight();
@@ -2597,6 +2605,7 @@ public class NotificationPanelView extends PanelView implements
}
mNotificationStackScroller.setExpandedHeight(expandedHeight);
updateKeyguardBottomAreaAlpha();
+ updateBigClockAlpha();
updateStatusBarIcons();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 18711c0d1ae3..e0c5e59b73f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -92,6 +92,8 @@ import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.NotificationChannels;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.List;
import java.util.Locale;
@@ -284,25 +286,6 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks,
});
}
- public void destroy() {
- mRotationLockController.removeCallback(this);
- mBluetooth.removeCallback(this);
- mProvisionedController.removeCallback(this);
- mZenController.removeCallback(this);
- mCast.removeCallback(mCastCallback);
- mHotspot.removeCallback(mHotspotCallback);
- mNextAlarmController.removeCallback(mNextAlarmCallback);
- mDataSaver.removeCallback(this);
- mKeyguardMonitor.removeCallback(this);
- mPrivacyItemController.removeCallback(this);
- SysUiServiceProvider.getComponent(mContext, CommandQueue.class).removeCallback(this);
- mContext.unregisterReceiver(mIntentReceiver);
-
- NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
- mCurrentNotifs.forEach(v -> noMan.cancelAsUser(v.first, SystemMessage.NOTE_INSTANT_APPS,
- new UserHandle(v.second)));
- }
-
@Override
public void onZenChanged(int zen) {
updateVolumeZen();
@@ -812,6 +795,15 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks,
boolean showMicrophone = false;
boolean showLocation = false;
for (PrivacyItem item : items) {
+ if (item == null /* b/124234367 */) {
+ if (DEBUG) {
+ Log.e(TAG, "updatePrivacyItems - null item found");
+ StringWriter out = new StringWriter();
+ mPrivacyItemController.dump(null, new PrintWriter(out), null);
+ Log.e(TAG, out.toString());
+ }
+ continue;
+ }
switch (item.getPrivacyType()) {
case TYPE_CAMERA:
showCamera = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index 84f1cef19b77..73ab5274a0ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -56,6 +56,7 @@ import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.system.InputChannelCompat.InputEventDispatcher;
import com.android.systemui.shared.system.NavigationBarCompat;
import java.io.PrintWriter;
@@ -676,8 +677,13 @@ public class QuickStepController implements GestureHelper {
}
private boolean proxyMotionEvents(MotionEvent event) {
- final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
event.transform(mTransformGlobalMatrix);
+ InputEventDispatcher dispatcher = mOverviewEventSender.getInputEventDispatcher();
+ if (dispatcher != null) {
+ dispatcher.dispatch(event);
+ }
+
+ final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
try {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
overviewProxy.onPreMotionEvent(mNavigationBarView.getDownHitTarget());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 9f3bec60cb6d..653ec50e7682 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -189,7 +189,6 @@ import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
@@ -653,7 +652,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mColorExtractor.addOnColorsChangedListener(this);
mStatusBarStateController.addCallback(this,
- StatusBarStateControllerImpl.RANK_STATUS_BAR);
+ SysuiStatusBarStateController.RANK_STATUS_BAR);
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mDreamManager = IDreamManager.Stub.asInterface(
@@ -1550,12 +1549,12 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
- mEntryManager.updateNotificationRanking(null /* rankingMap */);
+ mEntryManager.updateNotifications();
}
@Override
public void onAmbientStateChanged(NotificationEntry entry, boolean isAmbient) {
- mEntryManager.updateNotificationRanking(null);
+ mEntryManager.updateNotifications();
if (isAmbient) {
mDozeServiceHost.fireNotificationPulse();
} else if (!mAmbientPulseManager.hasNotifications()) {
@@ -2843,38 +2842,6 @@ public class StatusBar extends SystemUI implements DemoMode,
startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */);
}
- public void destroy() {
- // Begin old BaseStatusBar.destroy().
- mContext.unregisterReceiver(mBannerActionBroadcastReceiver);
- mLockscreenUserManager.destroy();
- try {
- mNotificationListener.unregisterAsSystemService();
- } catch (RemoteException e) {
- // Ignore.
- }
- mNotificationListController.destroy();
- // End old BaseStatusBar.destroy().
- if (mStatusBarWindow != null) {
- mWindowManager.removeViewImmediate(mStatusBarWindow);
- mStatusBarWindow = null;
- }
- mNavigationBarController.destroy();
- mContext.unregisterReceiver(mBroadcastReceiver);
- mContext.unregisterReceiver(mDemoReceiver);
- mAssistManager.destroy();
- mHeadsUpManager.destroy();
- mStatusBarStateController.removeCallback(this);
-
- if (mQSPanel != null && mQSPanel.getHost() != null) {
- mQSPanel.getHost().destroy();
- }
- Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(null);
- mDeviceProvisionedController.removeCallback(mUserSetupObserver);
- Dependency.get(ConfigurationController.class).removeCallback(this);
- mZenController.removeCallback(this);
- mAppOpsController.removeCallback(APP_OPS, this);
- }
-
private boolean mDemoModeAllowed;
private boolean mDemoMode;
@@ -4036,8 +4003,7 @@ public class StatusBar extends SystemUI implements DemoMode,
float viewY = screenY - mTmpInt2[1];
if (0 <= viewX && viewX <= mAmbientIndicationContainer.getWidth()
&& 0 <= viewY && viewY <= mAmbientIndicationContainer.getHeight()) {
- if (mAmbientIndicationContainer instanceof DozeReceiver)
- ((DozeReceiver) mAmbientIndicationContainer).onDozeDoubleTap();
+ dispatchTap(mAmbientIndicationContainer, viewX, viewY);
}
}
}
@@ -4052,6 +4018,12 @@ public class StatusBar extends SystemUI implements DemoMode,
mScrimController.setAodFrontScrimAlpha(scrimOpacity);
}
+ private void dispatchTap(View view, float x, float y) {
+ long now = SystemClock.elapsedRealtime();
+ dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_DOWN);
+ dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_UP);
+ }
+
private void dispatchTouchEvent(View view, float x, float y, long now, int action) {
MotionEvent ev = MotionEvent.obtain(now, now, action, x, y, 0 /* meta */);
view.dispatchTouchEvent(ev);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index e9705ff35a4d..3ce66c5de372 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -258,6 +258,11 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
}
}
+ @Override
+ public void onOverlayChanged() {
+ onDensityOrFontScaleChanged();
+ }
+
private void updateNotificationOnUiModeChanged() {
ArrayList<NotificationEntry> userNotifications
= mEntryManager.getNotificationData().getNotificationsForCurrentUser();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index 5d03f19f4655..b0d1106ecb24 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -35,7 +35,6 @@ import android.testing.TestableLooper.RunWithLooper;
import android.text.TextPaint;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextClock;
@@ -60,6 +59,8 @@ import org.mockito.MockitoAnnotations;
@RunWithLooper(setAsMainLooper = true)
public class KeyguardClockSwitchTest extends SysuiTestCase {
private FrameLayout mClockContainer;
+ private FrameLayout mBigClockContainer;
+ private TextClock mBigClock;
private StatusBarStateController.StateListener mStateListener;
@Mock
@@ -73,6 +74,8 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
mKeyguardClockSwitch =
(KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null);
mClockContainer = mKeyguardClockSwitch.findViewById(R.id.clock_view);
+ mBigClockContainer = new FrameLayout(getContext());
+ mBigClock = new TextClock(getContext());
MockitoAnnotations.initMocks(this);
when(mClockView.getPaint()).thenReturn(mock(TextPaint.class));
mStateListener = mKeyguardClockSwitch.getStateListener();
@@ -93,19 +96,17 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
@Test
public void onPluginConnected_showPluginBigClock() {
// GIVEN that the container for the big clock has visibility GONE
- FrameLayout bigClockContainer = new FrameLayout(getContext());
- bigClockContainer.setVisibility(GONE);
- mKeyguardClockSwitch.setBigClockContainer(bigClockContainer);
+ mBigClockContainer.setVisibility(GONE);
+ mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
// AND the plugin returns a view for the big clock
ClockPlugin plugin = mock(ClockPlugin.class);
- TextClock pluginView = new TextClock(getContext());
- when(plugin.getBigClockView()).thenReturn(pluginView);
+ when(plugin.getBigClockView()).thenReturn(mBigClock);
// WHEN the plugin is connected
mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
// THEN the big clock container is visible and it is the parent of the
// big clock view.
- assertThat(bigClockContainer.getVisibility()).isEqualTo(VISIBLE);
- assertThat(pluginView.getParent()).isEqualTo(bigClockContainer);
+ assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mBigClock.getParent()).isEqualTo(mBigClockContainer);
}
@Test
@@ -246,24 +247,64 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
@Test
public void onStateChanged_InvisibleInShade() {
// GIVEN that the big clock container is visible
- ViewGroup container = mock(ViewGroup.class);
- when(container.getVisibility()).thenReturn(View.VISIBLE);
- mKeyguardClockSwitch.setBigClockContainer(container);
+ mBigClockContainer.setVisibility(View.VISIBLE);
+ mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
// WHEN transitioned to SHADE state
mStateListener.onStateChanged(StatusBarState.SHADE);
// THEN the container is invisible.
- verify(container).setVisibility(View.INVISIBLE);
+ assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.INVISIBLE);
}
@Test
public void onStateChanged_VisibleInKeyguard() {
// GIVEN that the big clock container is invisible
- ViewGroup container = mock(ViewGroup.class);
- when(container.getVisibility()).thenReturn(View.INVISIBLE);
- mKeyguardClockSwitch.setBigClockContainer(container);
+ mBigClockContainer.setVisibility(View.INVISIBLE);
+ mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
// WHEN transitioned to KEYGUARD state
mStateListener.onStateChanged(StatusBarState.KEYGUARD);
// THEN the container is visible.
- verify(container).setVisibility(View.VISIBLE);
+ assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
+ @Test
+ public void setBigClockContainer_visible() {
+ // GIVEN that the big clock container is visible
+ mBigClockContainer.setVisibility(View.VISIBLE);
+ // AND GIVEN that a plugin is active.
+ ClockPlugin plugin = mock(ClockPlugin.class);
+ when(plugin.getBigClockView()).thenReturn(mBigClock);
+ mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ // WHEN the container is associated with the clock switch
+ mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ // THEN the container remains visible.
+ assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
+ @Test
+ public void setBigClockContainer_invisible() {
+ // GIVEN that the big clock container is invisible
+ mBigClockContainer.setVisibility(View.INVISIBLE);
+ // AND GIVEN that a plugin is active.
+ ClockPlugin plugin = mock(ClockPlugin.class);
+ when(plugin.getBigClockView()).thenReturn(mBigClock);
+ mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ // WHEN the container is associated with the clock switch
+ mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ // THEN the container remains invisible.
+ assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.INVISIBLE);
+ }
+
+ @Test
+ public void setBigClockContainer_gone() {
+ // GIVEN that the big clock container is gone
+ mBigClockContainer.setVisibility(View.GONE);
+ // AND GIVEN that a plugin is active.
+ ClockPlugin plugin = mock(ClockPlugin.class);
+ when(plugin.getBigClockView()).thenReturn(mBigClock);
+ mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ // WHEN the container is associated with the clock switch
+ mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ // THEN the container is made visible.
+ assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
index 77895c97051c..190ce7550511 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
@@ -75,6 +75,17 @@ public class KeyguardSliceViewTest extends SysuiTestCase {
}
@Test
+ public void hasHeader_readsSliceData() {
+ ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY);
+ mKeyguardSliceView.onChanged(builder.build());
+ Assert.assertFalse("View should not have a header", mKeyguardSliceView.hasHeader());
+
+ builder.setHeader(new ListBuilder.HeaderBuilder().setTitle("header title!"));
+ mKeyguardSliceView.onChanged(builder.build());
+ Assert.assertTrue("View should have a header", mKeyguardSliceView.hasHeader());
+ }
+
+ @Test
public void refresh_replacesSliceContentAndNotifiesListener() {
AtomicBoolean notified = new AtomicBoolean();
mKeyguardSliceView.setContentChangeListener(()-> notified.set(true));
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
new file mode 100644
index 000000000000..f813ac693d42
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.LeakCheck;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dock.DockManager;
+import com.android.systemui.dock.DockManagerFake;
+import com.android.systemui.utils.leaks.FakeExtensionController;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public final class ClockManagerTest extends SysuiTestCase {
+
+ private ClockManager mClockManager;
+ private LeakCheck mLeakCheck;
+ private FakeExtensionController mFakeExtensionController;
+ private DockManagerFake mFakeDockManager;
+ @Mock ClockManager.ClockChangedListener mMockListener;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mLeakCheck = new LeakCheck();
+ mFakeExtensionController = new FakeExtensionController(mLeakCheck);
+ mFakeDockManager = new DockManagerFake();
+ mClockManager = new ClockManager(getContext(), mFakeExtensionController,
+ mFakeDockManager);
+ mClockManager.addOnClockChangedListener(mMockListener);
+ }
+
+ @After
+ public void tearDown() {
+ mClockManager.removeOnClockChangedListener(mMockListener);
+ }
+
+ @Test
+ public void dockEvent() {
+ mFakeDockManager.setDockEvent(DockManager.STATE_DOCKED);
+ assertThat(mClockManager.isDocked()).isTrue();
+ }
+
+ @Test
+ public void undockEvent() {
+ mFakeDockManager.setDockEvent(DockManager.STATE_NONE);
+ assertThat(mClockManager.isDocked()).isFalse();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/DefaultClockSupplierTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/DefaultClockSupplierTest.java
new file mode 100644
index 000000000000..1a3b198ac0d6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/DefaultClockSupplierTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.LayoutInflater;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.ClockPlugin;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public final class DefaultClockSupplierTest extends SysuiTestCase {
+
+ private static final String BUBBLE_CLOCK = BubbleClockController.class.getName();
+ private static final Class<?> BUBBLE_CLOCK_CLASS = BubbleClockController.class;
+
+ private DefaultClockSupplier mDefaultClockSupplier;
+ @Mock SettingsWrapper mMockSettingsWrapper;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mDefaultClockSupplier = new DefaultClockSupplier(mMockSettingsWrapper,
+ LayoutInflater.from(getContext()));
+ }
+
+ @Test
+ public void get_default() {
+ // GIVEN that settings doesn't contain any values
+ when(mMockSettingsWrapper.getLockScreenCustomClockFace()).thenReturn(null);
+ when(mMockSettingsWrapper.getDockedClockFace()).thenReturn(null);
+ // WHEN get is called
+ ClockPlugin plugin = mDefaultClockSupplier.get();
+ // THEN the result is null, indicated the default clock face should be used.
+ assertThat(plugin).isNull();
+ }
+
+ @Test
+ public void get_customClock() {
+ // GIVEN that settings is set to the bubble clock face
+ when(mMockSettingsWrapper.getLockScreenCustomClockFace()).thenReturn(BUBBLE_CLOCK);
+ // WHEN get is called
+ ClockPlugin plugin = mDefaultClockSupplier.get();
+ // THEN the plugin is the bubble clock face.
+ assertThat(plugin).isInstanceOf(BUBBLE_CLOCK_CLASS);
+ }
+
+ @Test
+ public void get_badSettingsValue() {
+ // GIVEN that settings contains a value that doesn't correspond to a
+ // custom clock face.
+ when(mMockSettingsWrapper.getLockScreenCustomClockFace()).thenReturn("bad value");
+ // WHEN get is called
+ ClockPlugin plugin = mDefaultClockSupplier.get();
+ // THEN the result is null.
+ assertThat(plugin).isNull();
+ }
+
+ @Test
+ public void get_dockedDefault() {
+ // GIVEN docked
+ mDefaultClockSupplier.setDocked(true);
+ // WHEN get is called
+ ClockPlugin plugin = mDefaultClockSupplier.get();
+ // THEN the result is null, indicating the default clock face.
+ assertThat(plugin).isNull();
+ }
+
+ @Test
+ public void get_dockedCustomClock() {
+ // GIVEN docked and settings is set to the bubble clock face
+ mDefaultClockSupplier.setDocked(true);
+ when(mMockSettingsWrapper.getDockedClockFace()).thenReturn(BUBBLE_CLOCK);
+ // WHEN get is called
+ ClockPlugin plugin = mDefaultClockSupplier.get();
+ // THEN the plugin is the bubble clock face.
+ assertThat(plugin).isInstanceOf(BUBBLE_CLOCK_CLASS);
+ }
+
+ @Test
+ public void get_badDockedSettingsValue() {
+ // GIVEN docked and settings contains a value that doesn't correspond to
+ // an available clock face.
+ mDefaultClockSupplier.setDocked(true);
+ when(mMockSettingsWrapper.getDockedClockFace()).thenReturn("bad value");
+ // WHEN get is called
+ ClockPlugin plugin = mDefaultClockSupplier.get();
+ // THEN the result is null.
+ assertThat(plugin).isNull();
+ }
+
+ @Test
+ public void get_badDockedSettingsFallback() {
+ // GIVEN docked and settings contains a value that doesn't correspond to
+ // an available clock face, but locked screen settings is set to bubble
+ // clock.
+ mDefaultClockSupplier.setDocked(true);
+ when(mMockSettingsWrapper.getDockedClockFace()).thenReturn("bad value");
+ when(mMockSettingsWrapper.getLockScreenCustomClockFace()).thenReturn(BUBBLE_CLOCK);
+ // WHEN get is called
+ ClockPlugin plugin = mDefaultClockSupplier.get();
+ // THEN the plugin is the bubble clock face.
+ assertThat(plugin).isInstanceOf(BUBBLE_CLOCK_CLASS);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 2742577db860..ca72602f2c2b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -82,6 +82,8 @@ public class BubbleControllerTest extends SysuiTestCase {
@Mock
private BubbleController.BubbleExpandListener mBubbleExpandListener;
+ private BubbleData mBubbleData;
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -104,7 +106,9 @@ public class BubbleControllerTest extends SysuiTestCase {
when(mNotificationData.getChannel(mRow.getEntry().key)).thenReturn(mRow.getEntry().channel);
when(mNotificationData.getChannel(mNoChannelRow.getEntry().key)).thenReturn(null);
- mBubbleController = new TestableBubbleController(mContext, mStatusBarWindowController);
+ mBubbleData = new BubbleData();
+ mBubbleController = new TestableBubbleController(mContext, mStatusBarWindowController,
+ mBubbleData);
mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
mBubbleController.setExpandListener(mBubbleExpandListener);
@@ -207,12 +211,12 @@ public class BubbleControllerTest extends SysuiTestCase {
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().key);
// Last added is the one that is expanded
- assertEquals(mRow2.getEntry(), stackView.getExpandedBubble().getEntry());
+ assertEquals(mRow2.getEntry(), stackView.getExpandedBubbleView().getEntry());
assertFalse(mRow2.getEntry().showInShadeWhenBubble());
// Switch which bubble is expanded
stackView.setExpandedBubble(mRow.getEntry());
- assertEquals(mRow.getEntry(), stackView.getExpandedBubble().getEntry());
+ assertEquals(mRow.getEntry(), stackView.getExpandedBubbleView().getEntry());
assertFalse(mRow.getEntry().showInShadeWhenBubble());
// collapse for previous bubble
@@ -262,19 +266,19 @@ public class BubbleControllerTest extends SysuiTestCase {
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().key);
// Last added is the one that is expanded
- assertEquals(mRow2.getEntry(), stackView.getExpandedBubble().getEntry());
+ assertEquals(mRow2.getEntry(), stackView.getExpandedBubbleView().getEntry());
assertFalse(mRow2.getEntry().showInShadeWhenBubble());
// Dismiss currently expanded
- mBubbleController.removeBubble(stackView.getExpandedBubble().getKey());
+ mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey());
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().key);
// Make sure next bubble is selected
- assertEquals(mRow.getEntry(), stackView.getExpandedBubble().getEntry());
+ assertEquals(mRow.getEntry(), stackView.getExpandedBubbleView().getEntry());
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key);
// Dismiss that one
- mBubbleController.removeBubble(stackView.getExpandedBubble().getKey());
+ mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey());
// Make sure state changes and collapse happens
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().key);
@@ -297,8 +301,8 @@ public class BubbleControllerTest extends SysuiTestCase {
static class TestableBubbleController extends BubbleController {
TestableBubbleController(Context context,
- StatusBarWindowController statusBarWindowController) {
- super(context, statusBarWindowController);
+ StatusBarWindowController statusBarWindowController, BubbleData data) {
+ super(context, statusBarWindowController, data);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
index 98bf3c2743a8..bb384dd52875 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
@@ -18,6 +18,7 @@ package com.android.systemui.privacy
import android.app.ActivityManager
import android.app.AppOpsManager
+import android.content.Context
import android.content.Intent
import android.content.pm.UserInfo
import android.os.Handler
@@ -28,11 +29,18 @@ import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
import com.android.systemui.Dependency
+import com.android.systemui.Dependency.BG_HANDLER
+import com.android.systemui.Dependency.MAIN_HANDLER
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.appops.AppOpItem
import com.android.systemui.appops.AppOpsController
+import org.hamcrest.Matchers.hasItem
+import org.hamcrest.Matchers.not
+import org.hamcrest.Matchers.nullValue
import org.junit.Assert.assertEquals
+import org.junit.Assert.assertThat
+import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -81,15 +89,20 @@ class PrivacyItemControllerTest : SysuiTestCase() {
private lateinit var testableLooper: TestableLooper
private lateinit var privacyItemController: PrivacyItemController
+ private lateinit var handler: Handler
+
+ fun PrivacyItemController(context: Context) =
+ PrivacyItemController(context, appOpsController, handler, handler)
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
testableLooper = TestableLooper.get(this)
+ handler = Handler(testableLooper.looper)
appOpsController = mDependency.injectMockDependency(AppOpsController::class.java)
- mDependency.injectTestDependency(Dependency.BG_LOOPER, testableLooper.looper)
- mDependency.injectTestDependency(Dependency.MAIN_HANDLER, Handler(testableLooper.looper))
+ mDependency.injectTestDependency(Dependency.BG_HANDLER, handler)
+ mDependency.injectTestDependency(Dependency.MAIN_HANDLER, handler)
mContext.addMockSystemService(UserManager::class.java, userManager)
mContext.getOrCreateTestableResources().addOverride(R.string.device_services,
DEVICE_SERVICES_STRING)
@@ -232,4 +245,26 @@ class PrivacyItemControllerTest : SysuiTestCase() {
verify(callback, never()).privacyChanged(anyList())
verify(otherCallback).privacyChanged(anyList())
}
+
+ @Test
+ fun testListShouldNotHaveNull() {
+ doReturn(listOf(AppOpItem(AppOpsManager.OP_ACTIVATE_VPN, TEST_UID, "", 0),
+ AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, "", 0)))
+ .`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ privacyItemController.addCallback(callback)
+ testableLooper.processAllMessages()
+
+ verify(callback).privacyChanged(capture(argCaptor))
+ assertEquals(1, argCaptor.value.size)
+ assertThat(argCaptor.value, not(hasItem(nullValue())))
+ }
+
+ @Test
+ fun testListShouldBeCopy() {
+ val list = listOf(PrivacyItem(PrivacyType.TYPE_CAMERA,
+ PrivacyApplication("", TEST_UID, mContext)))
+ privacyItemController.privacyList = list
+ assertEquals(list, privacyItemController.privacyList)
+ assertTrue(list !== privacyItemController.privacyList)
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index cad1a96b8075..79bc0a39d59c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -521,6 +521,16 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
verify(extender2).setShouldManageLifetime(mEntry, false);
}
+ /**
+ * Ensure that calling NotificationEntryManager.performRemoveNotification() doesn't crash when
+ * given a notification that has already been removed from NotificationData.
+ */
+ @Test
+ public void testPerformRemoveNotification_removedEntry() {
+ mEntryManager.getNotificationData().remove(mSbn.getKey(), null /* ranking */);
+ mEntryManager.performRemoveNotification(mSbn);
+ }
+
private Notification.Action createAction() {
return new Notification.Action.Builder(
Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
index ba2aec0dd3e1..9f36a1eb9943 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
@@ -23,12 +23,19 @@ import static android.app.Notification.CATEGORY_CALL;
import static android.app.Notification.CATEGORY_EVENT;
import static android.app.Notification.CATEGORY_MESSAGE;
import static android.app.Notification.CATEGORY_REMINDER;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.IMPORTANCE_MIN;
+
+import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_CHANNEL;
+import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_IMPORTANCE;
+import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_VIS_EFFECTS;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -36,6 +43,7 @@ import static org.mockito.Mockito.when;
import android.Manifest;
import android.app.Notification;
import android.app.NotificationChannel;
+import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Person;
import android.content.Intent;
@@ -84,8 +92,6 @@ public class NotificationDataTest extends SysuiTestCase {
private static final int UID_NORMAL = 123;
private static final int UID_ALLOW_DURING_SETUP = 456;
- private static final String TEST_HIDDEN_NOTIFICATION_KEY = "testHiddenNotificationKey";
- private static final String TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY = "exempt";
private static final NotificationChannel NOTIFICATION_CHANNEL =
new NotificationChannel("id", "name", NotificationChannel.USER_LOCKED_IMPORTANCE);
@@ -97,7 +103,7 @@ public class NotificationDataTest extends SysuiTestCase {
NotificationData.KeyguardEnvironment mEnvironment;
private final IPackageManager mMockPackageManager = mock(IPackageManager.class);
- private NotificationData mNotificationData;
+ private TestableNotificationData mNotificationData;
private ExpandableNotificationRow mRow;
@Before
@@ -131,6 +137,7 @@ public class NotificationDataTest extends SysuiTestCase {
@Test
public void testChannelSetWhenAdded() {
+ mNotificationData.rankingOverrides.putParcelable(OVERRIDE_CHANNEL, NOTIFICATION_CHANNEL);
mNotificationData.add(mRow.getEntry());
assertEquals(NOTIFICATION_CHANNEL, mRow.getEntry().channel);
}
@@ -217,12 +224,12 @@ public class NotificationDataTest extends SysuiTestCase {
@Test
public void testIsExemptFromDndVisualSuppression_foreground() {
initStatusBarNotification(false);
- when(mMockStatusBarNotification.getKey()).thenReturn(
- TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
+
Notification n = mMockStatusBarNotification.getNotification();
n.flags = Notification.FLAG_FOREGROUND_SERVICE;
NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
mNotificationData.add(entry);
+ mNotificationData.rankingOverrides.putInt(OVERRIDE_VIS_EFFECTS, 255);
assertTrue(entry.isExemptFromDndVisualSuppression());
assertFalse(entry.shouldSuppressAmbient());
@@ -231,8 +238,6 @@ public class NotificationDataTest extends SysuiTestCase {
@Test
public void testIsExemptFromDndVisualSuppression_media() {
initStatusBarNotification(false);
- when(mMockStatusBarNotification.getKey()).thenReturn(
- TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
Notification n = mMockStatusBarNotification.getNotification();
Notification.Builder nb = Notification.Builder.recoverBuilder(mContext, n);
nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
@@ -240,6 +245,7 @@ public class NotificationDataTest extends SysuiTestCase {
when(mMockStatusBarNotification.getNotification()).thenReturn(n);
NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
mNotificationData.add(entry);
+ mNotificationData.rankingOverrides.putInt(OVERRIDE_VIS_EFFECTS, 255);
assertTrue(entry.isExemptFromDndVisualSuppression());
assertFalse(entry.shouldSuppressAmbient());
@@ -248,11 +254,10 @@ public class NotificationDataTest extends SysuiTestCase {
@Test
public void testIsExemptFromDndVisualSuppression_system() {
initStatusBarNotification(false);
- when(mMockStatusBarNotification.getKey()).thenReturn(
- TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
entry.mIsSystemNotification = true;
mNotificationData.add(entry);
+ mNotificationData.rankingOverrides.putInt(OVERRIDE_VIS_EFFECTS, 255);
assertTrue(entry.isExemptFromDndVisualSuppression());
assertFalse(entry.shouldSuppressAmbient());
@@ -261,10 +266,10 @@ public class NotificationDataTest extends SysuiTestCase {
@Test
public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() {
initStatusBarNotification(false);
- when(mMockStatusBarNotification.getKey()).thenReturn(
- TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
entry.mIsSystemNotification = true;
+ mNotificationData.rankingOverrides.putInt(OVERRIDE_VIS_EFFECTS,
+ NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT);
mNotificationData.add(entry);
when(mMockStatusBarNotification.getNotification()).thenReturn(
@@ -353,6 +358,64 @@ public class NotificationDataTest extends SysuiTestCase {
assertTrue(entry.isLastMessageFromReply());
}
+ @Test
+ public void personHighPriority() {
+ Person person = new Person.Builder()
+ .setName("name")
+ .setKey("abc")
+ .setUri("uri")
+ .setBot(true)
+ .build();
+
+ Notification notification = new Notification.Builder(mContext, "test")
+ .addPerson(person)
+ .build();
+
+ StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
+ notification, mContext.getUser(), "", 0);
+
+ assertTrue(mNotificationData.isHighPriority(sbn));
+ }
+
+ @Test
+ public void messagingStyleHighPriority() {
+
+ Notification notification = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.MessagingStyle(""))
+ .build();
+
+ StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
+ notification, mContext.getUser(), "", 0);
+
+ assertTrue(mNotificationData.isHighPriority(sbn));
+ }
+
+ @Test
+ public void minForegroundNotHighPriority() {
+ Notification notification = mock(Notification.class);
+ when(notification.isForegroundService()).thenReturn(true);
+
+ mNotificationData.rankingOverrides.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_MIN);
+
+ StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
+ notification, mContext.getUser(), "", 0);
+
+ assertFalse(mNotificationData.isHighPriority(sbn));
+ }
+
+ @Test
+ public void lowForegroundHighPriority() {
+ Notification notification = mock(Notification.class);
+ when(notification.isForegroundService()).thenReturn(true);
+
+ mNotificationData.rankingOverrides.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
+
+ StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
+ notification, mContext.getUser(), "", 0);
+
+ assertTrue(mNotificationData.isHighPriority(sbn));
+ }
+
private void initStatusBarNotification(boolean allowDuringSetup) {
Bundle bundle = new Bundle();
bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
@@ -362,39 +425,90 @@ public class NotificationDataTest extends SysuiTestCase {
when(mMockStatusBarNotification.getNotification()).thenReturn(notification);
}
- private class TestableNotificationData extends NotificationData {
+ public static class TestableNotificationData extends NotificationData {
public TestableNotificationData() {
super();
}
+ public static final String OVERRIDE_RANK = "r";
+ public static final String OVERRIDE_DND = "dnd";
+ public static final String OVERRIDE_VIS_OVERRIDE = "vo";
+ public static final String OVERRIDE_VIS_EFFECTS = "ve";
+ public static final String OVERRIDE_IMPORTANCE = "i";
+ public static final String OVERRIDE_IMP_EXP = "ie";
+ public static final String OVERRIDE_GROUP = "g";
+ public static final String OVERRIDE_CHANNEL = "c";
+ public static final String OVERRIDE_PEOPLE = "p";
+ public static final String OVERRIDE_SNOOZE_CRITERIA = "sc";
+ public static final String OVERRIDE_BADGE = "b";
+ public static final String OVERRIDE_USER_SENTIMENT = "us";
+ public static final String OVERRIDE_HIDDEN = "h";
+ public static final String OVERRIDE_LAST_ALERTED = "la";
+ public static final String OVERRIDE_NOISY = "n";
+ public static final String OVERRIDE_SMART_ACTIONS = "sa";
+ public static final String OVERRIDE_SMART_REPLIES = "sr";
+ public static final String OVERRIDE_BUBBLE = "cb";
+
+ public Bundle rankingOverrides = new Bundle();
+
@Override
protected boolean getRanking(String key, Ranking outRanking) {
super.getRanking(key, outRanking);
- if (key.equals(TEST_HIDDEN_NOTIFICATION_KEY)) {
- outRanking.populate(key, outRanking.getRank(),
- outRanking.matchesInterruptionFilter(),
- outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(),
- outRanking.getImportance(), outRanking.getImportanceExplanation(),
- outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
- outRanking.canShowBadge(), outRanking.getUserSentiment(), true,
- -1, false, null, null, outRanking.canBubble());
- } else if (key.equals(TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY)) {
- outRanking.populate(key, outRanking.getRank(),
- outRanking.matchesInterruptionFilter(),
- outRanking.getVisibilityOverride(), 255,
- outRanking.getImportance(), outRanking.getImportanceExplanation(),
- outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
- outRanking.canShowBadge(), outRanking.getUserSentiment(), true, -1,
- false, null, null, outRanking.canBubble());
- } else {
- outRanking.populate(key, outRanking.getRank(),
- outRanking.matchesInterruptionFilter(),
- outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(),
- outRanking.getImportance(), outRanking.getImportanceExplanation(),
- outRanking.getOverrideGroupKey(), NOTIFICATION_CHANNEL, null, null,
- outRanking.canShowBadge(), outRanking.getUserSentiment(), false, -1,
- false, null, null, outRanking.canBubble());
+
+ ArrayList<String> currentAdditionalPeople = new ArrayList<>();
+ if (outRanking.getAdditionalPeople() != null) {
+ currentAdditionalPeople.addAll(outRanking.getAdditionalPeople());
+ }
+
+ ArrayList<SnoozeCriterion> currentSnooze = new ArrayList<>();
+ if (outRanking.getSnoozeCriteria() != null) {
+ currentSnooze.addAll(outRanking.getSnoozeCriteria());
+ }
+
+ ArrayList<Notification.Action> currentActions = new ArrayList<>();
+ if (outRanking.getSmartActions() != null) {
+ currentActions.addAll(outRanking.getSmartActions());
}
+
+ ArrayList<CharSequence> currentReplies = new ArrayList<>();
+ if (outRanking.getSmartReplies() != null) {
+ currentReplies.addAll(outRanking.getSmartReplies());
+ }
+
+ outRanking.populate(key,
+ rankingOverrides.getInt(OVERRIDE_RANK, outRanking.getRank()),
+ rankingOverrides.getBoolean(OVERRIDE_DND,
+ outRanking.matchesInterruptionFilter()),
+ rankingOverrides.getInt(OVERRIDE_VIS_OVERRIDE,
+ outRanking.getVisibilityOverride()),
+ rankingOverrides.getInt(OVERRIDE_VIS_EFFECTS,
+ outRanking.getSuppressedVisualEffects()),
+ rankingOverrides.getInt(OVERRIDE_IMPORTANCE, outRanking.getImportance()),
+ rankingOverrides.getCharSequence(OVERRIDE_IMP_EXP,
+ outRanking.getImportanceExplanation()),
+ rankingOverrides.getString(OVERRIDE_GROUP, outRanking.getOverrideGroupKey()),
+ rankingOverrides.containsKey(OVERRIDE_CHANNEL)
+ ? (NotificationChannel) rankingOverrides.getParcelable(OVERRIDE_CHANNEL)
+ : outRanking.getChannel(),
+ rankingOverrides.containsKey(OVERRIDE_PEOPLE)
+ ? rankingOverrides.getStringArrayList(OVERRIDE_PEOPLE)
+ : currentAdditionalPeople,
+ rankingOverrides.containsKey(OVERRIDE_SNOOZE_CRITERIA)
+ ? rankingOverrides.getParcelableArrayList(OVERRIDE_SNOOZE_CRITERIA)
+ : currentSnooze,
+ rankingOverrides.getBoolean(OVERRIDE_BADGE, outRanking.canShowBadge()),
+ rankingOverrides.getInt(OVERRIDE_USER_SENTIMENT, outRanking.getUserSentiment()),
+ rankingOverrides.getBoolean(OVERRIDE_HIDDEN, outRanking.isSuspended()),
+ rankingOverrides.getLong(OVERRIDE_LAST_ALERTED,
+ outRanking.getLastAudiblyAlertedMillis()),
+ rankingOverrides.getBoolean(OVERRIDE_NOISY, outRanking.isNoisy()),
+ rankingOverrides.containsKey(OVERRIDE_SMART_ACTIONS)
+ ? rankingOverrides.getParcelableArrayList(OVERRIDE_SMART_ACTIONS)
+ : currentActions,
+ rankingOverrides.containsKey(OVERRIDE_SMART_REPLIES)
+ ? rankingOverrides.getCharSequenceArrayList(OVERRIDE_SMART_REPLIES)
+ : currentReplies,
+ rankingOverrides.getBoolean(OVERRIDE_BUBBLE, outRanking.canBubble()));
return true;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index 105bd9dd8793..19a73f6c2d5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -737,7 +737,7 @@ public class NotificationInfoTest extends SysuiTestCase {
guts.setGutsContent(mNotificationInfo);
mNotificationInfo.setGutsParent(guts);
- mNotificationInfo.findViewById(R.id.keep).performClick();
+ mNotificationInfo.findViewById(R.id.done).performClick();
verify(mBlockingHelperManager).dismissCurrentBlockingHelper();
mTestableLooper.processAllMessages();
@@ -765,7 +765,7 @@ public class NotificationInfoTest extends SysuiTestCase {
guts.setGutsContent(mNotificationInfo);
mNotificationInfo.setGutsParent(guts);
- mNotificationInfo.findViewById(R.id.keep).performClick();
+ mNotificationInfo.findViewById(R.id.done).performClick();
verify(mBlockingHelperManager).dismissCurrentBlockingHelper();
mTestableLooper.processAllMessages();
@@ -961,6 +961,41 @@ public class NotificationInfoTest extends SysuiTestCase {
}
@Test
+ public void testSilentlyChangedCallsUpdateNotificationChannel_blockingHelper()
+ throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_LOW);
+ mNotificationInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ 1 /* numChannels */,
+ mSbn,
+ null /* checkSaveListener */,
+ null /* onSettingsClick */,
+ null /* onAppSettingsClick */,
+ true /*provisioned */,
+ false /* isNonblockable */,
+ true /* isForBlockingHelper */,
+ true /* isUserSentimentNegative */,
+ IMPORTANCE_DEFAULT,
+ false);
+
+ mNotificationInfo.findViewById(R.id.deliver_silently).performClick();
+ waitForUndoButton();
+ mNotificationInfo.handleCloseControls(true, false);
+
+ mTestableLooper.processAllMessages();
+ ArgumentCaptor<NotificationChannel> updated =
+ ArgumentCaptor.forClass(NotificationChannel.class);
+ verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
+ anyString(), eq(TEST_UID), updated.capture());
+ assertTrue((updated.getValue().getUserLockedFields()
+ & USER_LOCKED_IMPORTANCE) != 0);
+ assertEquals(IMPORTANCE_LOW, updated.getValue().getImportance());
+ }
+
+ @Test
public void testKeepUpdatesNotificationChannel() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 3c910696ba60..d9adec85d40e 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6975,6 +6975,23 @@ message MetricsEvent {
// formerly: histogram system_cost_for_smart_sharing
FIELD_TIME_TO_APP_TARGETS = 1653;
+ // Open: Settings > Panel for Internet Connectivity
+ PANEL_INTERNET_CONNECTIVITY = 1654;
+
+ // Open: Settings > Panel for Volume
+ PANEL_VOLUME = 1655;
+
+ // Open: Settings > Panel for NFC
+ PANEL_NFC = 1656;
+
+ // Open: Settings > Panel for Media Output
+ PANEL_MEDIA_OUTPUT = 1657;
+
+ // ACTION: An interaction with a Slice or other component in the Panel.
+ // CATEGORY: SETTINGS
+ // OS: Q
+ ACTION_PANEL_INTERACTION = 1658;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 2b45b49ff322..ad0ed8beb7c5 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -515,6 +515,12 @@ message WifiLog {
// Total number of scan results for WPA3-Enterprise networks
optional int32 num_wpa3_enterprise_network_scan_results = 136;
+
+ // WifiConfigStore read/write metrics.
+ optional WifiConfigStoreIO wifi_config_store_io = 137;
+
+ // Total number of saved networks with mac randomization enabled.
+ optional int32 num_saved_networks_with_mac_randomization = 138;
}
// Information that gets logged for every WiFi connection.
@@ -668,6 +674,9 @@ message ConnectionEvent {
// Has bug report been taken.
optional bool automatic_bug_report_taken = 9;
+
+ // Connection is using locally generated random MAC address.
+ optional bool use_randomized_mac = 10 [default = false];
}
// Number of occurrences of a specific RSSI poll rssi value
@@ -1874,6 +1883,13 @@ message WifiUsabilityStatsEntry {
// Rx link speed at the sample time in Mbps
optional int32 rx_link_speed_mbps = 27;
+
+ // Sequence number generated by framework
+ optional int32 seq_num_inside_framework = 28;
+
+ // Whether current entry is for the same BSSID on the same frequency compared
+ // to last entry
+ optional bool is_same_bssid_and_freq = 29;
}
message WifiUsabilityStats {
@@ -2170,3 +2186,25 @@ message WifiDppLog {
EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK = 9;
}
}
+
+// WifiConfigStore read/write metrics.
+message WifiConfigStoreIO {
+ // Histogram of config store read durations.
+ repeated DurationBucket read_durations = 1;
+
+ // Histogram of config store write durations.
+ repeated DurationBucket write_durations = 2;
+
+ // Total Number of instances of write/read duration in this duration bucket.
+ message DurationBucket {
+ // Bucket covers duration : [range_start_ms, range_end_ms)
+ // The (inclusive) lower bound of read/write duration represented by this bucket
+ optional int32 range_start_ms = 1;
+
+ // The (exclusive) upper bound of read/write duration represented by this bucket
+ optional int32 range_end_ms = 2;
+
+ // Number of read/write durations that fit into this bucket
+ optional int32 count = 3;
+ }
+}
diff --git a/sax/tests/saxtests/Android.bp b/sax/tests/saxtests/Android.bp
new file mode 100644
index 000000000000..5889f769a645
--- /dev/null
+++ b/sax/tests/saxtests/Android.bp
@@ -0,0 +1,11 @@
+android_test {
+ name: "FrameworksSaxTests",
+ // Include all test java files.
+ srcs: ["src/**/*.java"],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ static_libs: ["junit"],
+ platform_apis: true,
+}
diff --git a/sax/tests/saxtests/Android.mk b/sax/tests/saxtests/Android.mk
deleted file mode 100644
index c4517a9a954a..000000000000
--- a/sax/tests/saxtests/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-LOCAL_PACKAGE_NAME := FrameworksSaxTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
-
diff --git a/services/accessibility/OWNERS b/services/accessibility/OWNERS
new file mode 100644
index 000000000000..265674a74b7e
--- /dev/null
+++ b/services/accessibility/OWNERS
@@ -0,0 +1,3 @@
+svetoslavganov@google.com
+pweaver@google.com
+rhedjao@google.com
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 2e45fa72eaac..4a3f12674eb7 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -49,6 +49,7 @@ import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.DeviceConfig;
import android.provider.Settings;
import android.service.autofill.FillEventHistory;
import android.service.autofill.UserData;
@@ -167,10 +168,14 @@ public final class AutofillManagerService
mUi = new AutoFillUI(ActivityThread.currentActivityThread().getSystemUiContext());
mAm = LocalServices.getService(ActivityManagerInternal.class);
+ DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_AUTOFILL,
+ ActivityThread.currentApplication().getMainExecutor(),
+ (namespace, name, value) -> setSmartSuggestionModesFromDeviceConfig(value));
+
setLogLevelFromSettings();
setMaxPartitionsFromSettings();
setMaxVisibleDatasetsFromSettings();
- setSmartSuggestionEmulationFromSettings();
+ setSmartSuggestionModesFromDeviceConfig();
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
@@ -197,9 +202,6 @@ public final class AutofillManagerService
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS), false, observer,
UserHandle.USER_ALL);
- resolver.registerContentObserver(Settings.Global.getUriFor(
- Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS), false, observer,
- UserHandle.USER_ALL);
}
@Override // from AbstractMasterSystemService
@@ -214,9 +216,6 @@ public final class AutofillManagerService
case Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS:
setMaxVisibleDatasetsFromSettings();
break;
- case Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS:
- setSmartSuggestionEmulationFromSettings();
- break;
default:
Slog.w(TAG, "Unexpected property (" + property + "); updating cache instead");
// fall through
@@ -457,14 +456,25 @@ public final class AutofillManagerService
}
}
- private void setSmartSuggestionEmulationFromSettings() {
- final int flags = Settings.Global.getInt(getContext().getContentResolver(),
- Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS, 0);
- if (sDebug) {
- Slog.d(TAG, "setSmartSuggestionEmulationFromSettings(): "
- + getSmartSuggestionModeToString(flags));
- }
+ private void setSmartSuggestionModesFromDeviceConfig() {
+ final String value = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_AUTOFILL,
+ AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES);
+ setSmartSuggestionModesFromDeviceConfig(value);
+ }
+ private void setSmartSuggestionModesFromDeviceConfig(@Nullable String value) {
+ if (sDebug) Slog.d(TAG, "setSmartSuggestionEmulationFromDeviceConfig(): value=" + value);
+ final int flags;
+ if (value == null) {
+ flags = AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
+ } else {
+ try {
+ flags = Integer.parseInt(value);
+ } catch (Exception e) {
+ Slog.w(TAG, "setSmartSuggestionEmulationFromDeviceConfig(): NAN:" + value);
+ return;
+ }
+ }
synchronized (mLock) {
mSupportedSmartSuggestionModes = flags;
}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index 9b863a9f2d26..61f63d3bbc3d 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -47,7 +47,7 @@ final class RemoteAugmentedAutofillService
private static final String TAG = RemoteAugmentedAutofillService.class.getSimpleName();
- private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.SECOND_IN_MILLIS;
+ private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
RemoteAugmentedAutofillService(Context context, ComponentName serviceName,
int userId, RemoteAugmentedAutofillServiceCallbacks callbacks,
@@ -106,6 +106,12 @@ final class RemoteAugmentedAutofillService
activityComponent, focusedId, focusedValue));
}
+ @Override
+ public String toString() {
+ return "RemoteAugmentedAutofillService["
+ + ComponentName.flattenToShortString(getComponentName()) + "]";
+ }
+
/**
* Called by {@link Session} when it's time to destroy all augmented autofill requests.
*/
@@ -181,11 +187,13 @@ final class RemoteAugmentedAutofillService
@Override
protected void onTimeout(RemoteAugmentedAutofillService remoteService) {
- Slog.wtf(TAG, "timed out: " + this);
+ // TODO(b/122858578): must update the logged AUTOFILL_AUGMENTED_REQUEST with the
+ // timeout
+ Slog.w(TAG, "PendingAutofillRequest timed out (" + TIMEOUT_REMOTE_REQUEST_MILLIS
+ + "ms) for " + remoteService);
// NOTE: so far we don't need notify RemoteAugmentedAutofillServiceCallbacks
finish();
}
-
}
public interface RemoteAugmentedAutofillServiceCallbacks
diff --git a/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListing.java b/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListingMap.java
index 2d2e88afccf1..a44890118717 100644
--- a/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListing.java
+++ b/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListingMap.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -11,13 +11,14 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
package com.android.server.backup.encryption.chunk;
import android.annotation.Nullable;
import android.util.proto.ProtoInputStream;
+
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
@@ -30,16 +31,16 @@ import java.util.Map;
* It can then tell the server to use that chunk, through telling it the position and length of the
* chunk in the previous backup's blob.
*/
-public class ChunkListing {
+public class ChunkListingMap {
/**
- * Reads a ChunkListing from a {@link ProtoInputStream}. Expects the message to be of format
+ * Reads a ChunkListingMap from a {@link ProtoInputStream}. Expects the message to be of format
* {@link ChunksMetadataProto.ChunkListing}.
*
* @param inputStream Currently at a {@link ChunksMetadataProto.ChunkListing} message.
* @throws IOException when the message is not structured as expected or a field can not be
* read.
*/
- public static ChunkListing readFromProto(ProtoInputStream inputStream) throws IOException {
+ public static ChunkListingMap readFromProto(ProtoInputStream inputStream) throws IOException {
Map<ChunkHash, Entry> entries = new HashMap();
long start = 0;
@@ -54,12 +55,12 @@ public class ChunkListing {
}
}
- return new ChunkListing(entries);
+ return new ChunkListingMap(entries);
}
private final Map<ChunkHash, Entry> mChunksByHash;
- private ChunkListing(Map<ChunkHash, Entry> chunksByHash) {
+ private ChunkListingMap(Map<ChunkHash, Entry> chunksByHash) {
mChunksByHash = Collections.unmodifiableMap(new HashMap<>(chunksByHash));
}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 9249c9cc023a..4afbc641ea6c 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -23,6 +23,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
+import android.app.ActivityThread;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -39,6 +40,7 @@ import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.DeviceConfig;
import android.provider.Settings;
import android.util.LocalLog;
import android.util.Slog;
@@ -89,19 +91,38 @@ public final class ContentCaptureManagerService extends
@Nullable
private SparseBooleanArray mDisabledUsers;
+ /**
+ * Global kill-switch based on value defined by
+ * {@link ContentCaptureManager#DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED}.
+ */
+ @GuardedBy("mLock")
+ @Nullable
+ private boolean mDisabledByDeviceConfig;
public ContentCaptureManagerService(@NonNull Context context) {
super(context, new FrameworkResourcesServiceNameResolver(context,
com.android.internal.R.string.config_defaultContentCaptureService),
UserManager.DISALLOW_CONTENT_CAPTURE);
- // Sets which serviecs are disabled
+ DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ ActivityThread.currentApplication().getMainExecutor(),
+ (namespace, key, value) -> {
+ if (!ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED
+ .equals(key)) {
+ Slog.i(mTag, "Ignoring change on " + key);
+ return;
+ }
+ setDisabledByDeviceConfig(value);
+ });
+ setDisabledByDeviceConfig();
+
+ // Sets which services are disabled
final UserManager um = getContext().getSystemService(UserManager.class);
final List<UserInfo> users = um.getUsers();
for (int i = 0; i < users.size(); i++) {
final int userId = users.get(i).id;
- final boolean disabled = isDisabledBySettings(userId);
+ final boolean disabled = mDisabledByDeviceConfig || isDisabledBySettings(userId);
if (disabled) {
- Slog.i(mTag, "user " + userId + " disabled by settings");
+ Slog.i(mTag, "user " + userId + " disabled by settings or device config");
if (mDisabledUsers == null) {
mDisabledUsers = new SparseBooleanArray(1);
}
@@ -160,7 +181,8 @@ public final class ContentCaptureManagerService extends
@Override // from AbstractMasterSystemService
protected boolean isDisabledLocked(@UserIdInt int userId) {
- return isDisabledBySettingsLocked(userId) || super.isDisabledLocked(userId);
+ return mDisabledByDeviceConfig || isDisabledBySettingsLocked(userId)
+ || super.isDisabledLocked(userId);
}
private boolean isDisabledBySettingsLocked(@UserIdInt int userId) {
@@ -191,6 +213,45 @@ public final class ContentCaptureManagerService extends
return false;
}
+ private void setDisabledByDeviceConfig() {
+ final String value = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED);
+ setDisabledByDeviceConfig(value);
+ }
+
+ private void setDisabledByDeviceConfig(@Nullable String value) {
+ if (verbose) Slog.v(mTag, "setDisabledByDeviceConfig(): value=" + value);
+ final UserManager um = getContext().getSystemService(UserManager.class);
+ final List<UserInfo> users = um.getUsers();
+
+ final boolean newDisabledValue;
+
+ if (value != null && value.equalsIgnoreCase("false")) {
+ newDisabledValue = true;
+ } else {
+ newDisabledValue = false;
+ }
+
+ synchronized (mLock) {
+ if (mDisabledByDeviceConfig == newDisabledValue) {
+ if (verbose) {
+ Slog.v(mTag, "setDisabledByDeviceConfig(): already " + newDisabledValue);
+ }
+ return;
+ }
+ mDisabledByDeviceConfig = newDisabledValue;
+
+ Slog.i(mTag, "setDisabledByDeviceConfig(): set to " + mDisabledByDeviceConfig);
+ for (int i = 0; i < users.size(); i++) {
+ final int userId = users.get(i).id;
+ boolean disabled = mDisabledByDeviceConfig || isDisabledBySettingsLocked(userId);
+ Slog.i(mTag, "setDisabledByDeviceConfig(): updating service for user "
+ + userId + " to " + (disabled ? "'disabled'" : "'enabled'"));
+ updateCachedServiceLocked(userId, disabled);
+ }
+ }
+ }
+
private void setContentCaptureFeatureEnabledForUser(@UserIdInt int userId, boolean enabled) {
synchronized (mLock) {
if (mDisabledUsers == null) {
@@ -338,6 +399,8 @@ public final class ContentCaptureManagerService extends
super.dumpLocked(prefix, pw);
pw.print(prefix); pw.print("Disabled users: "); pw.println(mDisabledUsers);
+ pw.print(prefix); pw.print("Disabled by DeviceConfig: ");
+ pw.println(mDisabledByDeviceConfig);
}
final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
@@ -406,7 +469,7 @@ public final class ContentCaptureManagerService extends
"isContentCaptureFeatureEnabled()", userId, Binder.getCallingUid(), result);
if (!isService) return;
- enabled = !isDisabledBySettingsLocked(userId);
+ enabled = !mDisabledByDeviceConfig && !isDisabledBySettingsLocked(userId);
}
try {
result.send(enabled ? ContentCaptureManager.RESULT_CODE_TRUE
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java
index 39d5c9d0b777..86ad52d9a42b 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java
@@ -77,15 +77,12 @@ public final class ContentCaptureManagerServiceShellCommand extends ShellCommand
pw.println(" Temporarily (for DURATION ms) changes the service implemtation.");
pw.println(" To reset, call with just the USER_ID argument.");
pw.println("");
- pw.println("");
pw.println(" set default-service-enabled USER_ID [true|false]");
pw.println(" Enable / disable the default service for the user.");
pw.println("");
- pw.println("");
pw.println(" get default-service-enabled USER_ID");
pw.println(" Checks whether the default service is enabled for the user.");
pw.println("");
- pw.println("");
pw.println(" list sessions [--user USER_ID]");
pw.println(" Lists all pending sessions.");
pw.println("");
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
index 3c52e17ce1e8..4ed5c3d263b6 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
@@ -37,6 +37,9 @@ final class ContentCaptureServerSession {
final IBinder mActivityToken;
private final ContentCapturePerUserService mService;
private final RemoteContentCaptureService mRemoteService;
+
+ // NOTE: this is the "internal" context (like package and taskId), not the explicit content
+ // set by apps - those are only send to the ContentCaptureService.
private final ContentCaptureContext mContentCaptureContext;
/**
diff --git a/services/core/java/com/android/server/AlarmManagerInternal.java b/services/core/java/com/android/server/AlarmManagerInternal.java
index 275661084aa3..5b0de5e2aae0 100644
--- a/services/core/java/com/android/server/AlarmManagerInternal.java
+++ b/services/core/java/com/android/server/AlarmManagerInternal.java
@@ -26,6 +26,8 @@ public interface AlarmManagerInternal {
void broadcastAlarmComplete(int recipientUid);
}
+ /** Returns true if AlarmManager is delaying alarms due to device idle. */
+ boolean isIdling();
public void removeAlarmsForUid(int uid);
public void registerInFlightListener(InFlightListener callback);
}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 10b532700d1b..a400cc384a58 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1991,6 +1991,11 @@ class AlarmManagerService extends SystemService {
*/
private final class LocalService implements AlarmManagerInternal {
@Override
+ public boolean isIdling() {
+ return isIdlingImpl();
+ }
+
+ @Override
public void removeAlarmsForUid(int uid) {
synchronized (mLock) {
removeLocked(uid);
@@ -2823,6 +2828,12 @@ class AlarmManagerService extends SystemService {
}
}
+ private boolean isIdlingImpl() {
+ synchronized (mLock) {
+ return mPendingIdleUntil != null;
+ }
+ }
+
AlarmManager.AlarmClockInfo getNextAlarmClockImpl(int userId) {
synchronized (mLock) {
return mNextAlarmClockForUser.get(userId);
diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java
index eafa0e2a6786..e51025943df4 100644
--- a/services/core/java/com/android/server/BinderCallsStatsService.java
+++ b/services/core/java/com/android/server/BinderCallsStatsService.java
@@ -121,6 +121,8 @@ public class BinderCallsStatsService extends Binder {
private static final String SETTINGS_DETAILED_TRACKING_KEY = "detailed_tracking";
private static final String SETTINGS_UPLOAD_DATA_KEY = "upload_data";
private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval";
+ private static final String SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY = "track_screen_state";
+ private static final String SETTINGS_TRACK_DIRECT_CALLING_UID_KEY = "track_calling_uid";
private static final String SETTINGS_MAX_CALL_STATS_KEY = "max_call_stats_count";
private boolean mEnabled;
@@ -169,6 +171,12 @@ public class BinderCallsStatsService extends Binder {
mBinderCallsStats.setMaxBinderCallStats(mParser.getInt(
SETTINGS_MAX_CALL_STATS_KEY,
BinderCallsStats.MAX_BINDER_CALL_STATS_COUNT_DEFAULT));
+ mBinderCallsStats.setTrackScreenInteractive(
+ mParser.getBoolean(SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY,
+ BinderCallsStats.DEFAULT_TRACK_SCREEN_INTERACTIVE));
+ mBinderCallsStats.setTrackDirectCallerUid(
+ mParser.getBoolean(SETTINGS_TRACK_DIRECT_CALLING_UID_KEY,
+ BinderCallsStats.DEFAULT_TRACK_DIRECT_CALLING_UID));
final boolean enabled =
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index fe4411c1dbb5..dad428acbfee 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -38,7 +38,6 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkPolicyManager.RULE_NONE;
import static android.net.NetworkPolicyManager.uidRulesToString;
-import static android.net.NetworkStack.NETWORKSTACK_PACKAGE_NAME;
import static android.net.shared.NetworkMonitorUtils.isValidationRequired;
import static android.net.shared.NetworkParcelableUtil.toStableParcelable;
import static android.os.Process.INVALID_UID;
@@ -2667,9 +2666,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
@Override
- public void showProvisioningNotification(String action) {
+ public void showProvisioningNotification(String action, String packageName) {
final Intent intent = new Intent(action);
- intent.setPackage(NETWORKSTACK_PACKAGE_NAME);
+ intent.setPackage(packageName);
final PendingIntent pendingIntent;
// Only the system server can register notifications with package "android"
@@ -2843,6 +2842,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (DBG) {
log(nai.name() + " got DISCONNECTED, was satisfying " + nai.numNetworkRequests());
}
+ // Clear all notifications of this network.
+ mNotifier.clearNotification(nai.network.netId);
// A network agent has disconnected.
// TODO - if we move the logic to the network agent (have them disconnect
// because they lost all their requests or because their score isn't good)
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 39030aaf3eb4..6b663941f8fb 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -271,6 +271,7 @@ public class DeviceIdleController extends SystemService
private static final int EVENT_BUFFER_SIZE = 100;
private AlarmManager mAlarmManager;
+ private AlarmManagerInternal mLocalAlarmManager;
private IBatteryStats mBatteryStats;
private ActivityManagerInternal mLocalActivityManager;
private ActivityTaskManagerInternal mLocalActivityTaskManager;
@@ -616,7 +617,8 @@ public class DeviceIdleController extends SystemService
}
};
- private final AlarmManager.OnAlarmListener mDeepAlarmListener
+ @VisibleForTesting
+ final AlarmManager.OnAlarmListener mDeepAlarmListener
= new AlarmManager.OnAlarmListener() {
@Override
public void onAlarm() {
@@ -1874,6 +1876,7 @@ public class DeviceIdleController extends SystemService
if (phase == PHASE_SYSTEM_SERVICES_READY) {
synchronized (this) {
mAlarmManager = mInjector.getAlarmManager();
+ mLocalAlarmManager = getLocalService(AlarmManagerInternal.class);
mBatteryStats = BatteryStatsService.getService();
mLocalActivityManager = getLocalService(ActivityManagerInternal.class);
mLocalActivityTaskManager = getLocalService(ActivityTaskManagerInternal.class);
@@ -2605,6 +2608,16 @@ public class DeviceIdleController extends SystemService
// next natural time to come out of it.
}
+
+ /** Returns true if the screen is locked. */
+ @VisibleForTesting
+ boolean isKeyguardShowing() {
+ synchronized (this) {
+ return mScreenLocked;
+ }
+ }
+
+ @VisibleForTesting
void keyguardShowingLocked(boolean showing) {
if (DEBUG) Slog.i(TAG, "keyguardShowing=" + showing);
if (mScreenLocked != showing) {
@@ -2616,25 +2629,38 @@ public class DeviceIdleController extends SystemService
}
}
+ @VisibleForTesting
void scheduleReportActiveLocked(String activeReason, int activeUid) {
Message msg = mHandler.obtainMessage(MSG_REPORT_ACTIVE, activeUid, 0, activeReason);
mHandler.sendMessage(msg);
}
void becomeActiveLocked(String activeReason, int activeUid) {
- if (DEBUG) Slog.i(TAG, "becomeActiveLocked, reason = " + activeReason);
+ becomeActiveLocked(activeReason, activeUid, mConstants.INACTIVE_TIMEOUT, true);
+ }
+
+ private void becomeActiveLocked(String activeReason, int activeUid,
+ long newInactiveTimeout, boolean changeLightIdle) {
+ if (DEBUG) {
+ Slog.i(TAG, "becomeActiveLocked, reason=" + activeReason
+ + ", changeLightIdle=" + changeLightIdle);
+ }
if (mState != STATE_ACTIVE || mLightState != STATE_ACTIVE) {
EventLogTags.writeDeviceIdle(STATE_ACTIVE, activeReason);
- EventLogTags.writeDeviceIdleLight(LIGHT_STATE_ACTIVE, activeReason);
- scheduleReportActiveLocked(activeReason, activeUid);
mState = STATE_ACTIVE;
- mLightState = LIGHT_STATE_ACTIVE;
- mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
+ mInactiveTimeout = newInactiveTimeout;
mCurIdleBudget = 0;
mMaintenanceStartTime = 0;
resetIdleManagementLocked();
- resetLightIdleManagementLocked();
- addEvent(EVENT_NORMAL, activeReason);
+
+ if (changeLightIdle) {
+ EventLogTags.writeDeviceIdleLight(LIGHT_STATE_ACTIVE, activeReason);
+ mLightState = LIGHT_STATE_ACTIVE;
+ resetLightIdleManagementLocked();
+ // Only report active if light is also ACTIVE.
+ scheduleReportActiveLocked(activeReason, activeUid);
+ addEvent(EVENT_NORMAL, activeReason);
+ }
}
}
@@ -2654,50 +2680,82 @@ public class DeviceIdleController extends SystemService
}
}
+ /** Sanity check to make sure DeviceIdleController and AlarmManager are on the same page. */
+ private void verifyAlarmStateLocked() {
+ if (mState == STATE_ACTIVE && mNextAlarmTime != 0) {
+ Slog.wtf(TAG, "mState=ACTIVE but mNextAlarmTime=" + mNextAlarmTime);
+ }
+ if (mState != STATE_IDLE && mLocalAlarmManager.isIdling()) {
+ Slog.wtf(TAG, "mState=" + stateToString(mState) + " but AlarmManager is idling");
+ }
+ if (mState == STATE_IDLE && !mLocalAlarmManager.isIdling()) {
+ Slog.wtf(TAG, "mState=IDLE but AlarmManager is not idling");
+ }
+ if (mLightState == LIGHT_STATE_ACTIVE && mNextLightAlarmTime != 0) {
+ Slog.wtf(TAG, "mLightState=ACTIVE but mNextLightAlarmTime is "
+ + TimeUtils.formatDuration(mNextLightAlarmTime - SystemClock.elapsedRealtime())
+ + " from now");
+ }
+ }
+
void becomeInactiveIfAppropriateLocked() {
- if (DEBUG) Slog.d(TAG, "becomeInactiveIfAppropriateLocked()");
- if ((!mScreenOn && !mCharging) || mForceIdle) {
- // Become inactive and determine if we will ultimately go idle.
- if (mDeepEnabled) {
- if (mQuickDozeActivated) {
- if (mState == STATE_QUICK_DOZE_DELAY || mState == STATE_IDLE
- || mState == STATE_IDLE_MAINTENANCE) {
- // Already "idling". Don't want to restart the process.
- // mLightState can't be LIGHT_STATE_ACTIVE if mState is any of these 3
- // values, so returning here is safe.
- return;
- }
- if (DEBUG) {
- Slog.d(TAG, "Moved from "
- + stateToString(mState) + " to STATE_QUICK_DOZE_DELAY");
- }
- mState = STATE_QUICK_DOZE_DELAY;
- // Make sure any motion sensing or locating is stopped.
- resetIdleManagementLocked();
- // Wait a small amount of time in case something (eg: background service from
- // recently closed app) needs to finish running.
- scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false);
- EventLogTags.writeDeviceIdle(mState, "no activity");
- } else if (mState == STATE_ACTIVE) {
- mState = STATE_INACTIVE;
- if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE");
- resetIdleManagementLocked();
- long delay = mInactiveTimeout;
- if (shouldUseIdleTimeoutFactorLocked()) {
- delay = (long) (mPreIdleFactor * delay);
- }
- scheduleAlarmLocked(delay, false);
- EventLogTags.writeDeviceIdle(mState, "no activity");
+ verifyAlarmStateLocked();
+
+ final boolean isScreenBlockingInactive =
+ mScreenOn && (!mConstants.WAIT_FOR_UNLOCK || !mScreenLocked);
+ if (DEBUG) {
+ Slog.d(TAG, "becomeInactiveIfAppropriateLocked():"
+ + " isScreenBlockingInactive=" + isScreenBlockingInactive
+ + " (mScreenOn=" + mScreenOn
+ + ", WAIT_FOR_UNLOCK=" + mConstants.WAIT_FOR_UNLOCK
+ + ", mScreenLocked=" + mScreenLocked + ")"
+ + " mCharging=" + mCharging
+ + " mForceIdle=" + mForceIdle
+ );
+ }
+ if (!mForceIdle && (mCharging || isScreenBlockingInactive)) {
+ return;
+ }
+ // Become inactive and determine if we will ultimately go idle.
+ if (mDeepEnabled) {
+ if (mQuickDozeActivated) {
+ if (mState == STATE_QUICK_DOZE_DELAY || mState == STATE_IDLE
+ || mState == STATE_IDLE_MAINTENANCE) {
+ // Already "idling". Don't want to restart the process.
+ // mLightState can't be LIGHT_STATE_ACTIVE if mState is any of these 3
+ // values, so returning here is safe.
+ return;
}
- }
- if (mLightState == LIGHT_STATE_ACTIVE && mLightEnabled) {
- mLightState = LIGHT_STATE_INACTIVE;
- if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE");
- resetLightIdleManagementLocked();
- scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);
- EventLogTags.writeDeviceIdleLight(mLightState, "no activity");
+ if (DEBUG) {
+ Slog.d(TAG, "Moved from "
+ + stateToString(mState) + " to STATE_QUICK_DOZE_DELAY");
+ }
+ mState = STATE_QUICK_DOZE_DELAY;
+ // Make sure any motion sensing or locating is stopped.
+ resetIdleManagementLocked();
+ // Wait a small amount of time in case something (eg: background service from
+ // recently closed app) needs to finish running.
+ scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false);
+ EventLogTags.writeDeviceIdle(mState, "no activity");
+ } else if (mState == STATE_ACTIVE) {
+ mState = STATE_INACTIVE;
+ if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE");
+ resetIdleManagementLocked();
+ long delay = mInactiveTimeout;
+ if (shouldUseIdleTimeoutFactorLocked()) {
+ delay = (long) (mPreIdleFactor * delay);
+ }
+ scheduleAlarmLocked(delay, false);
+ EventLogTags.writeDeviceIdle(mState, "no activity");
}
}
+ if (mLightState == LIGHT_STATE_ACTIVE && mLightEnabled) {
+ mLightState = LIGHT_STATE_INACTIVE;
+ if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE");
+ resetLightIdleManagementLocked();
+ scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);
+ EventLogTags.writeDeviceIdleLight(mLightState, "no activity");
+ }
}
private void resetIdleManagementLocked() {
@@ -3216,33 +3274,10 @@ public class DeviceIdleController extends SystemService
// The device is not yet active, so we want to go back to the pending idle
// state to wait again for no motion. Note that we only monitor for motion
// after moving out of the inactive state, so no need to worry about that.
- boolean becomeInactive = false;
- if (mState != STATE_ACTIVE) {
- // Motion shouldn't affect light state, if it's already in doze-light or maintenance
- boolean lightIdle = mLightState == LIGHT_STATE_IDLE
- || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK
- || mLightState == LIGHT_STATE_IDLE_MAINTENANCE;
- if (!lightIdle) {
- // Only switch to active state if we're not in either idle state
- scheduleReportActiveLocked(type, Process.myUid());
- addEvent(EVENT_NORMAL, type);
- }
- mActiveReason = ACTIVE_REASON_MOTION;
- mState = STATE_ACTIVE;
- mInactiveTimeout = timeout;
- mCurIdleBudget = 0;
- mMaintenanceStartTime = 0;
- EventLogTags.writeDeviceIdle(mState, type);
- becomeInactive = true;
- updateActiveConstraintsLocked();
- }
- if (mLightState == LIGHT_STATE_OVERRIDE) {
- // We went out of light idle mode because we had started deep idle mode... let's
- // now go back and reset things so we resume light idling if appropriate.
- mLightState = LIGHT_STATE_ACTIVE;
- EventLogTags.writeDeviceIdleLight(mLightState, type);
- becomeInactive = true;
- }
+ final boolean becomeInactive = mState != STATE_ACTIVE
+ || mLightState == LIGHT_STATE_OVERRIDE;
+ // We only want to change the IDLE state if it's OVERRIDE.
+ becomeActiveLocked(type, Process.myUid(), timeout, mLightState == LIGHT_STATE_OVERRIDE);
if (becomeInactive) {
becomeInactiveIfAppropriateLocked();
}
diff --git a/services/core/java/com/android/server/ExtconUEventObserver.java b/services/core/java/com/android/server/ExtconUEventObserver.java
index b3084f50071f..eb591528bc90 100644
--- a/services/core/java/com/android/server/ExtconUEventObserver.java
+++ b/services/core/java/com/android/server/ExtconUEventObserver.java
@@ -22,8 +22,11 @@ import android.util.Slog;
import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.regex.Pattern;
/**
* A specialized UEventObserver that receives UEvents from the kernel for devices in the {@code
@@ -40,13 +43,14 @@ import java.util.Map;
* time in that process. Once started the UEvent thread will not stop (although it can stop
* notifying UEventObserver's via stopObserving()).
*
- * <p>
- *
* @hide
*/
public abstract class ExtconUEventObserver extends UEventObserver {
private static final String TAG = "ExtconUEventObserver";
private static final boolean LOG = false;
+ private static final String SELINUX_POLICIES_NEED_TO_BE_CHANGED =
+ "This probably means the selinux policies need to be changed.";
+
private final Map<String, ExtconInfo> mExtconInfos = new ArrayMap<>();
@Override
@@ -70,15 +74,47 @@ public abstract class ExtconUEventObserver extends UEventObserver {
/** Starts observing {@link ExtconInfo#getDevicePath()}. */
public void startObserving(ExtconInfo extconInfo) {
- mExtconInfos.put(extconInfo.getDevicePath(), extconInfo);
- if (LOG) Slog.v(TAG, "Observing " + extconInfo.getDevicePath());
- startObserving("DEVPATH=" + extconInfo.getDevicePath());
+ String devicePath = extconInfo.getDevicePath();
+ if (devicePath == null) {
+ Slog.wtf(TAG, "Unable to start observing " + extconInfo.getName()
+ + " because the device path is null. " + SELINUX_POLICIES_NEED_TO_BE_CHANGED);
+ } else {
+ mExtconInfos.put(devicePath, extconInfo);
+ if (LOG) Slog.v(TAG, "Observing " + devicePath);
+ startObserving("DEVPATH=" + devicePath);
+ }
}
/** An External Connection to watch. */
public static final class ExtconInfo {
private static final String TAG = "ExtconInfo";
+ /** Returns a new list of all external connections whose name matches {@code regex}. */
+ public static List<ExtconInfo> getExtconInfos(@Nullable String regex) {
+ Pattern p = regex == null ? null : Pattern.compile(regex);
+ File file = new File("/sys/class/extcon");
+ File[] files = file.listFiles();
+ if (files == null) {
+ Slog.wtf(TAG, file + " exists " + file.exists() + " isDir " + file.isDirectory()
+ + " but listFiles returns null. "
+ + SELINUX_POLICIES_NEED_TO_BE_CHANGED);
+ return new ArrayList<>(0); // Always return a new list.
+ } else {
+ ArrayList list = new ArrayList(files.length);
+ for (File f : files) {
+ String name = f.getName();
+ if (p == null || p.matcher(name).matches()) {
+ ExtconInfo uei = new ExtconInfo(name);
+ list.add(uei);
+ if (LOG) Slog.d(TAG, name + " matches " + regex);
+ } else {
+ if (LOG) Slog.d(TAG, name + " does not match " + regex);
+ }
+ }
+ return list;
+ }
+ }
+
private final String mName;
public ExtconInfo(String name) {
@@ -123,6 +159,15 @@ public abstract class ExtconUEventObserver extends UEventObserver {
/** Does the {@link /sys/class/extcon} directory exist */
public static boolean extconExists() {
File extconDir = new File("/sys/class/extcon");
- return extconDir.exists() && extconDir.isDirectory();
+ boolean retVal = extconDir.exists() && extconDir.isDirectory();
+ // TODO(b/124364409): return the correct value after selinux policy is updated.
+ if (retVal) {
+ Slog.w(TAG, extconDir + " exists " + extconDir.exists() + " isDir "
+ + extconDir.isDirectory()
+ + " but reporting it does not exist until selinux policies are updated."
+ + " see b/124364409"
+ );
+ }
+ return false;
}
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 4834ce0da9b3..9d92ea2b5b45 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -67,6 +67,7 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IInterface;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
@@ -109,6 +110,7 @@ import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
import com.android.server.location.LocationRequestStatistics.PackageStatistics;
import com.android.server.location.MockProvider;
import com.android.server.location.PassiveProvider;
+import com.android.server.location.RemoteListenerHelper;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -121,6 +123,8 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
+import java.util.function.Consumer;
+import java.util.function.Function;
/**
* The service class that manages LocationProviders and issues location
@@ -225,11 +229,14 @@ public class LocationManagerService extends ILocationManager.Stub {
private final ArraySet<String> mIgnoreSettingsPackageWhitelist = new ArraySet<>();
@GuardedBy("mLock")
- private final ArrayMap<IBinder, CallerIdentity> mGnssMeasurementsListeners = new ArrayMap<>();
-
+ private final ArrayMap<IBinder, LinkedListener<IGnssMeasurementsListener>>
+ mGnssMeasurementsListeners = new ArrayMap<>();
@GuardedBy("mLock")
- private final ArrayMap<IBinder, CallerIdentity>
+ private final ArrayMap<IBinder, LinkedListener<IGnssNavigationMessageListener>>
mGnssNavigationMessageListeners = new ArrayMap<>();
+ @GuardedBy("mLock")
+ private final ArrayMap<IBinder, LinkedListener<IGnssStatusListener>>
+ mGnssStatusListeners = new ArrayMap<>();
// current active user on the device - other users are denied location data
private int mCurrentUserId = UserHandle.USER_SYSTEM;
@@ -243,7 +250,7 @@ public class LocationManagerService extends ILocationManager.Stub {
@GuardedBy("mLock")
private IBatchedLocationCallback mGnssBatchingCallback;
@GuardedBy("mLock")
- private LinkedCallback mGnssBatchingDeathCallback;
+ private LinkedListener<IBatchedLocationCallback> mGnssBatchingDeathCallback;
@GuardedBy("mLock")
private boolean mGnssBatchingInProgress = false;
@@ -485,7 +492,7 @@ public class LocationManagerService extends ILocationManager.Stub {
&& record.mIsForegroundUid != foreground) {
if (D) {
Log.d(TAG, "request from uid " + uid + " is now "
- + (foreground ? "foreground" : "background)"));
+ + foregroundAsString(foreground));
}
record.updateForeground(foreground);
@@ -499,44 +506,48 @@ public class LocationManagerService extends ILocationManager.Stub {
applyRequirementsLocked(provider);
}
- for (Entry<IBinder, CallerIdentity> entry : mGnssMeasurementsListeners.entrySet()) {
- CallerIdentity callerIdentity = entry.getValue();
- if (callerIdentity.mUid == uid) {
- if (D) {
- Log.d(TAG, "gnss measurements listener from uid " + uid
- + " is now " + (foreground ? "foreground" : "background)"));
- }
- if (foreground || isThrottlingExemptLocked(entry.getValue())) {
- mGnssMeasurementsProvider.addListener(
- IGnssMeasurementsListener.Stub.asInterface(entry.getKey()),
- callerIdentity);
- } else {
- mGnssMeasurementsProvider.removeListener(
- IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
- }
+ updateGnssDataProviderOnUidImportanceChangedLocked(mGnssMeasurementsListeners,
+ mGnssMeasurementsProvider, IGnssMeasurementsListener.Stub::asInterface,
+ uid, foreground);
+
+ updateGnssDataProviderOnUidImportanceChangedLocked(mGnssNavigationMessageListeners,
+ mGnssNavigationMessageProvider, IGnssNavigationMessageListener.Stub::asInterface,
+ uid, foreground);
+
+ updateGnssDataProviderOnUidImportanceChangedLocked(mGnssStatusListeners,
+ mGnssStatusProvider, IGnssStatusListener.Stub::asInterface, uid, foreground);
+ }
+
+ @GuardedBy("mLock")
+ private <TListener extends IInterface> void updateGnssDataProviderOnUidImportanceChangedLocked(
+ ArrayMap<IBinder, ? extends LinkedListenerBase> gnssDataListeners,
+ RemoteListenerHelper<TListener> gnssDataProvider,
+ Function<IBinder, TListener> mapBinderToListener, int uid, boolean foreground) {
+ for (Entry<IBinder, ? extends LinkedListenerBase> entry : gnssDataListeners.entrySet()) {
+ LinkedListenerBase linkedListener = entry.getValue();
+ CallerIdentity callerIdentity = linkedListener.mCallerIdentity;
+ if (callerIdentity.mUid != uid) {
+ continue;
}
- }
- for (Entry<IBinder, CallerIdentity> entry : mGnssNavigationMessageListeners.entrySet()) {
- CallerIdentity callerIdentity = entry.getValue();
- if (callerIdentity.mUid == uid) {
- if (D) {
- Log.d(TAG, "gnss navigation message listener from uid "
- + uid + " is now "
- + (foreground ? "foreground" : "background)"));
- }
- if (foreground || isThrottlingExemptLocked(entry.getValue())) {
- mGnssNavigationMessageProvider.addListener(
- IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()),
- callerIdentity);
- } else {
- mGnssNavigationMessageProvider.removeListener(
- IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
- }
+ if (D) {
+ Log.d(TAG, linkedListener.mListenerName + " from uid "
+ + uid + " is now " + foregroundAsString(foreground));
+ }
+
+ TListener listener = mapBinderToListener.apply(entry.getKey());
+ if (foreground || isThrottlingExemptLocked(callerIdentity)) {
+ gnssDataProvider.addListener(listener, callerIdentity);
+ } else {
+ gnssDataProvider.removeListener(listener);
}
}
}
+ private static String foregroundAsString(boolean foreground) {
+ return foreground ? "foreground" : "background";
+ }
+
private static boolean isImportanceForeground(int importance) {
return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
}
@@ -1218,9 +1229,8 @@ public class LocationManagerService extends ILocationManager.Stub {
* A wrapper class holding either an ILocationListener or a PendingIntent to receive
* location updates.
*/
- private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
+ private final class Receiver extends LinkedListenerBase implements PendingIntent.OnFinished {
private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
- final CallerIdentity mCallerIdentity;
private final int mAllowedResolutionLevel; // resolution level allowed to receiver
private final ILocationListener mListener;
@@ -1240,6 +1250,7 @@ public class LocationManagerService extends ILocationManager.Stub {
private Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
String packageName, WorkSource workSource, boolean hideFromAppOps) {
+ super(new CallerIdentity(uid, pid, packageName), "LocationListener");
mListener = listener;
mPendingIntent = intent;
if (listener != null) {
@@ -1248,7 +1259,6 @@ public class LocationManagerService extends ILocationManager.Stub {
mKey = intent;
}
mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
- mCallerIdentity = new CallerIdentity(uid, pid, packageName);
if (workSource != null && workSource.isEmpty()) {
workSource = null;
}
@@ -1486,7 +1496,7 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public void binderDied() {
- if (D) Log.d(TAG, "Location listener died");
+ if (D) Log.d(TAG, "Remote " + mListenerName + " died.");
synchronized (mLock) {
removeUpdatesLocked(this);
@@ -1617,53 +1627,29 @@ public class LocationManagerService extends ILocationManager.Stub {
return false;
}
+ CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(),
+ Binder.getCallingPid(), packageName);
synchronized (mLock) {
mGnssBatchingCallback = callback;
- mGnssBatchingDeathCallback = new LinkedCallback(callback);
- try {
- callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
- } catch (RemoteException e) {
- // if the remote process registering the listener is already dead, just swallow the
- // exception and return
- Log.e(TAG, "Remote listener already died.", e);
+ mGnssBatchingDeathCallback = new LinkedListener<>(callback,
+ "BatchedLocationCallback", callerIdentity,
+ (IBatchedLocationCallback listener) -> {
+ stopGnssBatch();
+ removeGnssBatchingCallback();
+ });
+ if (!linkToListenerDeathNotificationLocked(callback.asBinder(),
+ mGnssBatchingDeathCallback)) {
return false;
}
-
return true;
}
}
- private class LinkedCallback implements IBinder.DeathRecipient {
- private final IBatchedLocationCallback mCallback;
-
- private LinkedCallback(@NonNull IBatchedLocationCallback callback) {
- mCallback = callback;
- }
-
- @NonNull
- public IBatchedLocationCallback getUnderlyingListener() {
- return mCallback;
- }
-
- @Override
- public void binderDied() {
- Log.d(TAG, "Remote Batching Callback died: " + mCallback);
- stopGnssBatch();
- removeGnssBatchingCallback();
- }
- }
-
@Override
public void removeGnssBatchingCallback() {
synchronized (mLock) {
- try {
- mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
- 0 /* flags */);
- } catch (NoSuchElementException e) {
- // if the death callback isn't connected (it should be...), log error, swallow the
- // exception and return
- Log.e(TAG, "Couldn't unlink death callback.", e);
- }
+ unlinkFromListenerDeathNotificationLocked(mGnssBatchingCallback.asBinder(),
+ mGnssBatchingDeathCallback);
mGnssBatchingCallback = null;
mGnssBatchingDeathCallback = null;
}
@@ -2053,7 +2039,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
if (!provider.isUseableLocked()) {
if (isSettingsExemptLocked(record)) {
- providerRequest.forceLocation = true;
+ providerRequest.locationSettingsIgnored = true;
providerRequest.lowPowerMode = false;
} else {
continue;
@@ -2063,8 +2049,9 @@ public class LocationManagerService extends ILocationManager.Stub {
LocationRequest locationRequest = record.mRealRequest;
long interval = locationRequest.getInterval();
+
// if we're forcing location, don't apply any throttling
- if (!providerRequest.forceLocation && !isThrottlingExemptLocked(
+ if (!providerRequest.locationSettingsIgnored && !isThrottlingExemptLocked(
record.mReceiver.mCallerIdentity)) {
if (!record.mIsForegroundUid) {
interval = Math.max(interval, backgroundThrottleInterval);
@@ -2264,10 +2251,8 @@ public class LocationManagerService extends ILocationManager.Stub {
if (receiver == null) {
receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
hideFromAppOps);
- try {
- receiver.getListener().asBinder().linkToDeath(receiver, 0);
- } catch (RemoteException e) {
- Slog.e(TAG, "linkToDeath failed:", e);
+ if (!linkToListenerDeathNotificationLocked(receiver.getListener().asBinder(),
+ receiver)) {
return null;
}
mReceivers.put(binder, receiver);
@@ -2482,7 +2467,8 @@ public class LocationManagerService extends ILocationManager.Stub {
if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
- receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
+ unlinkFromListenerDeathNotificationLocked(receiver.getListener().asBinder(),
+ receiver);
receiver.clearPendingBroadcastsLocked();
}
@@ -2694,43 +2680,137 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
- public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
- if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
- return false;
- }
-
- return mGnssStatusProvider.addListener(callback, new CallerIdentity(Binder.getCallingUid(),
- Binder.getCallingPid(), packageName));
+ public boolean registerGnssStatusCallback(IGnssStatusListener listener, String packageName) {
+ return addGnssDataListener(listener, packageName, "GnssStatusListener",
+ mGnssStatusProvider, mGnssStatusListeners,
+ this::unregisterGnssStatusCallback);
}
@Override
- public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
- mGnssStatusProvider.removeListener(callback);
+ public void unregisterGnssStatusCallback(IGnssStatusListener listener) {
+ removeGnssDataListener(listener, mGnssStatusProvider, mGnssStatusListeners);
}
@Override
public boolean addGnssMeasurementsListener(
IGnssMeasurementsListener listener, String packageName) {
- if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
+ return addGnssDataListener(listener, packageName, "GnssMeasurementsListener",
+ mGnssMeasurementsProvider, mGnssMeasurementsListeners,
+ this::removeGnssMeasurementsListener);
+ }
+
+ @Override
+ public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
+ removeGnssDataListener(listener, mGnssMeasurementsProvider, mGnssMeasurementsListeners);
+ }
+
+ private abstract static class LinkedListenerBase implements IBinder.DeathRecipient {
+ protected final CallerIdentity mCallerIdentity;
+ protected final String mListenerName;
+
+ private LinkedListenerBase(@NonNull CallerIdentity callerIdentity,
+ @NonNull String listenerName) {
+ mCallerIdentity = callerIdentity;
+ mListenerName = listenerName;
+ }
+ }
+
+ private static class LinkedListener<TListener> extends LinkedListenerBase {
+ private final TListener mListener;
+ private final Consumer<TListener> mBinderDeathCallback;
+
+ private LinkedListener(@NonNull TListener listener, String listenerName,
+ @NonNull CallerIdentity callerIdentity,
+ @NonNull Consumer<TListener> binderDeathCallback) {
+ super(callerIdentity, listenerName);
+ mListener = listener;
+ mBinderDeathCallback = binderDeathCallback;
+ }
+
+ @Override
+ public void binderDied() {
+ if (D) Log.d(TAG, "Remote " + mListenerName + " died.");
+ mBinderDeathCallback.accept(mListener);
+ }
+ }
+
+ private <TListener extends IInterface> boolean addGnssDataListener(
+ TListener listener, String packageName, String listenerName,
+ RemoteListenerHelper<TListener> gnssDataProvider,
+ ArrayMap<IBinder, LinkedListener<TListener>> gnssDataListeners,
+ Consumer<TListener> binderDeathCallback) {
+ if (!hasGnssPermissions(packageName) || gnssDataProvider == null) {
return false;
}
+ CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(),
+ Binder.getCallingPid(), packageName);
+ LinkedListener<TListener> linkedListener = new LinkedListener<>(listener,
+ listenerName, callerIdentity, binderDeathCallback);
+ IBinder binder = listener.asBinder();
synchronized (mLock) {
- CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(),
- Binder.getCallingPid(), packageName);
- mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity);
+ if (!linkToListenerDeathNotificationLocked(binder, linkedListener)) {
+ return false;
+ }
+
+ gnssDataListeners.put(binder, linkedListener);
long identity = Binder.clearCallingIdentity();
try {
if (isThrottlingExemptLocked(callerIdentity)
|| isImportanceForeground(
mActivityManager.getPackageImportance(packageName))) {
- return mGnssMeasurementsProvider.addListener(listener, callerIdentity);
+ gnssDataProvider.addListener(listener, callerIdentity);
}
+ return true;
} finally {
Binder.restoreCallingIdentity(identity);
}
+ }
+ }
+
+ private <TListener extends IInterface> void removeGnssDataListener(
+ TListener listener, RemoteListenerHelper<TListener> gnssDataProvider,
+ ArrayMap<IBinder, LinkedListener<TListener>> gnssDataListeners) {
+ if (gnssDataProvider == null) {
+ return;
+ }
+
+ IBinder binder = listener.asBinder();
+ synchronized (mLock) {
+ LinkedListener<TListener> linkedListener = gnssDataListeners.remove(binder);
+ if (linkedListener == null) {
+ return;
+ }
+ unlinkFromListenerDeathNotificationLocked(binder, linkedListener);
+ gnssDataProvider.removeListener(listener);
+ }
+ }
+ private boolean linkToListenerDeathNotificationLocked(IBinder binder,
+ LinkedListenerBase linkedListener) {
+ try {
+ binder.linkToDeath(linkedListener, 0 /* flags */);
return true;
+ } catch (RemoteException e) {
+ // if the remote process registering the listener is already dead, just swallow the
+ // exception and return
+ Log.w(TAG, "Could not link " + linkedListener.mListenerName + " death callback.",
+ e);
+ return false;
+ }
+ }
+
+ private boolean unlinkFromListenerDeathNotificationLocked(IBinder binder,
+ LinkedListenerBase linkedListener) {
+ try {
+ binder.unlinkToDeath(linkedListener, 0 /* flags */);
+ return true;
+ } catch (NoSuchElementException e) {
+ // if the death callback isn't connected (it should be...), log error,
+ // swallow the exception and return
+ Log.w(TAG, "Could not unlink " + linkedListener.mListenerName + " death callback.",
+ e);
+ return false;
}
}
@@ -2759,53 +2839,17 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
- public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
- if (mGnssMeasurementsProvider == null) {
- return;
- }
-
- synchronized (mLock) {
- mGnssMeasurementsListeners.remove(listener.asBinder());
- mGnssMeasurementsProvider.removeListener(listener);
- }
- }
-
- @Override
public boolean addGnssNavigationMessageListener(
- IGnssNavigationMessageListener listener,
- String packageName) {
- if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
- return false;
- }
-
- synchronized (mLock) {
- CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(),
- Binder.getCallingPid(), packageName);
-
- mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
- long identity = Binder.clearCallingIdentity();
- try {
- if (isThrottlingExemptLocked(callerIdentity)
- || isImportanceForeground(
- mActivityManager.getPackageImportance(packageName))) {
- return mGnssNavigationMessageProvider.addListener(listener, callerIdentity);
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
-
- return true;
- }
+ IGnssNavigationMessageListener listener, String packageName) {
+ return addGnssDataListener(listener, packageName, "GnssNavigationMessageListener",
+ mGnssNavigationMessageProvider, mGnssNavigationMessageListeners,
+ this::removeGnssNavigationMessageListener);
}
@Override
public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
- if (mGnssNavigationMessageProvider != null) {
- synchronized (mLock) {
- mGnssNavigationMessageListeners.remove(listener.asBinder());
- mGnssNavigationMessageProvider.removeListener(listener);
- }
- }
+ removeGnssDataListener(listener, mGnssNavigationMessageProvider,
+ mGnssNavigationMessageListeners);
}
@Override
@@ -3368,18 +3412,14 @@ public class LocationManagerService extends ILocationManager.Stub {
pw.println(" " + record);
}
}
+
pw.println(" Active GnssMeasurement Listeners:");
- for (CallerIdentity callerIdentity : mGnssMeasurementsListeners.values()) {
- pw.println(" " + callerIdentity.mPid + " " + callerIdentity.mUid + " "
- + callerIdentity.mPackageName + ": "
- + isThrottlingExemptLocked(callerIdentity));
- }
+ dumpGnssDataListenersLocked(pw, mGnssMeasurementsListeners);
pw.println(" Active GnssNavigationMessage Listeners:");
- for (CallerIdentity callerIdentity : mGnssNavigationMessageListeners.values()) {
- pw.println(" " + callerIdentity.mPid + " " + callerIdentity.mUid + " "
- + callerIdentity.mPackageName + ": "
- + isThrottlingExemptLocked(callerIdentity));
- }
+ dumpGnssDataListenersLocked(pw, mGnssNavigationMessageListeners);
+ pw.println(" Active GnssStatus Listeners:");
+ dumpGnssDataListenersLocked(pw, mGnssStatusListeners);
+
pw.println(" Historical Records by Provider:");
for (Map.Entry<PackageProviderKey, PackageStatistics> entry
: mRequestStatistics.statistics.entrySet()) {
@@ -3432,4 +3472,15 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
}
+
+ @GuardedBy("mLock")
+ private void dumpGnssDataListenersLocked(PrintWriter pw,
+ ArrayMap<IBinder, ? extends LinkedListenerBase> gnssDataListeners) {
+ for (LinkedListenerBase listener : gnssDataListeners.values()) {
+ CallerIdentity callerIdentity = listener.mCallerIdentity;
+ pw.println(" " + callerIdentity.mPid + " " + callerIdentity.mUid + " "
+ + callerIdentity.mPackageName + ": "
+ + isThrottlingExemptLocked(callerIdentity));
+ }
+ }
}
diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java
index 9184128d466f..c334540f48cc 100644
--- a/services/core/java/com/android/server/LooperStatsService.java
+++ b/services/core/java/com/android/server/LooperStatsService.java
@@ -51,16 +51,19 @@ public class LooperStatsService extends Binder {
private static final String LOOPER_STATS_SERVICE_NAME = "looper_stats";
private static final String SETTINGS_ENABLED_KEY = "enabled";
private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval";
+ private static final String SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY = "track_screen_state";
private static final String DEBUG_SYS_LOOPER_STATS_ENABLED =
"debug.sys.looper_stats_enabled";
private static final int DEFAULT_SAMPLING_INTERVAL = 100;
private static final int DEFAULT_ENTRIES_SIZE_CAP = 2000;
private static final boolean DEFAULT_ENABLED = true;
+ private static final boolean DEFAULT_TRACK_SCREEN_INTERACTIVE = false;
private final Context mContext;
private final LooperStats mStats;
// Default should be false so that the first call to #setEnabled installed the looper observer.
private boolean mEnabled = false;
+ private boolean mTrackScreenInteractive = false;
private LooperStatsService(Context context, LooperStats stats) {
this.mContext = context;
@@ -79,6 +82,9 @@ public class LooperStatsService extends Binder {
setSamplingInterval(
parser.getInt(SETTINGS_SAMPLING_INTERVAL_KEY, DEFAULT_SAMPLING_INTERVAL));
+ setTrackScreenInteractive(
+ parser.getBoolean(SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY,
+ DEFAULT_TRACK_SCREEN_INTERACTIVE));
// Manually specified value takes precedence over Settings.
setEnabled(SystemProperties.getBoolean(
DEBUG_SYS_LOOPER_STATS_ENABLED,
@@ -155,6 +161,13 @@ public class LooperStatsService extends Binder {
}
}
+ private void setTrackScreenInteractive(boolean enabled) {
+ if (mTrackScreenInteractive != enabled) {
+ mTrackScreenInteractive = enabled;
+ mStats.reset();
+ }
+ }
+
private void setSamplingInterval(int samplingInterval) {
if (samplingInterval > 0) {
mStats.setSamplingInterval(samplingInterval);
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index f505b76178a4..dc394d0ad482 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -20,18 +20,18 @@ import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.NETWORK_SETTINGS;
import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.SHUTDOWN;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
+import static android.net.INetd.FIREWALL_BLACKLIST;
+import static android.net.INetd.FIREWALL_CHAIN_DOZABLE;
+import static android.net.INetd.FIREWALL_CHAIN_NONE;
+import static android.net.INetd.FIREWALL_CHAIN_POWERSAVE;
+import static android.net.INetd.FIREWALL_CHAIN_STANDBY;
+import static android.net.INetd.FIREWALL_RULE_ALLOW;
+import static android.net.INetd.FIREWALL_RULE_DENY;
+import static android.net.INetd.FIREWALL_WHITELIST;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NONE;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
-import static android.net.NetworkPolicyManager.FIREWALL_TYPE_BLACKLIST;
-import static android.net.NetworkPolicyManager.FIREWALL_TYPE_WHITELIST;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.STATS_PER_UID;
import static android.net.NetworkStats.TAG_ALL;
@@ -1946,7 +1946,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
int numUids = 0;
if (DBG) Slog.d(TAG, "Closing sockets after enabling chain " + chainName);
- if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) {
+ if (getFirewallType(chain) == FIREWALL_WHITELIST) {
// Close all sockets on all non-system UIDs...
ranges = new UidRange[] {
// TODO: is there a better way of finding all existing users? If so, we could
@@ -1958,7 +1958,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
final SparseIntArray rules = getUidFirewallRulesLR(chain);
exemptUids = new int[rules.size()];
for (int i = 0; i < exemptUids.length; i++) {
- if (rules.valueAt(i) == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
+ if (rules.valueAt(i) == FIREWALL_RULE_ALLOW) {
exemptUids[numUids] = rules.keyAt(i);
numUids++;
}
@@ -1980,7 +1980,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
final SparseIntArray rules = getUidFirewallRulesLR(chain);
ranges = new UidRange[rules.size()];
for (int i = 0; i < ranges.length; i++) {
- if (rules.valueAt(i) == NetworkPolicyManager.FIREWALL_RULE_DENY) {
+ if (rules.valueAt(i) == FIREWALL_RULE_DENY) {
int uid = rules.keyAt(i);
ranges[numUids] = new UidRange(uid, uid);
numUids++;
@@ -2052,13 +2052,13 @@ public class NetworkManagementService extends INetworkManagementService.Stub
private int getFirewallType(int chain) {
switch (chain) {
case FIREWALL_CHAIN_STANDBY:
- return FIREWALL_TYPE_BLACKLIST;
+ return FIREWALL_BLACKLIST;
case FIREWALL_CHAIN_DOZABLE:
- return FIREWALL_TYPE_WHITELIST;
+ return FIREWALL_WHITELIST;
case FIREWALL_CHAIN_POWERSAVE:
- return FIREWALL_TYPE_WHITELIST;
+ return FIREWALL_WHITELIST;
default:
- return isFirewallEnabled() ? FIREWALL_TYPE_WHITELIST : FIREWALL_TYPE_BLACKLIST;
+ return isFirewallEnabled() ? FIREWALL_WHITELIST : FIREWALL_BLACKLIST;
}
}
@@ -2160,14 +2160,14 @@ public class NetworkManagementService extends INetworkManagementService.Stub
private @NonNull String getFirewallRuleName(int chain, int rule) {
String ruleName;
- if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) {
- if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
+ if (getFirewallType(chain) == FIREWALL_WHITELIST) {
+ if (rule == FIREWALL_RULE_ALLOW) {
ruleName = "allow";
} else {
ruleName = "deny";
}
} else { // Blacklist mode
- if (rule == NetworkPolicyManager.FIREWALL_RULE_DENY) {
+ if (rule == FIREWALL_RULE_DENY) {
ruleName = "deny";
} else {
ruleName = "allow";
@@ -2194,7 +2194,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
private int getFirewallRuleType(int chain, int rule) {
if (rule == NetworkPolicyManager.FIREWALL_RULE_DEFAULT) {
- return getFirewallType(chain) == FIREWALL_TYPE_WHITELIST
+ return getFirewallType(chain) == FIREWALL_WHITELIST
? INetd.FIREWALL_RULE_DENY : INetd.FIREWALL_RULE_ALLOW;
}
return rule;
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index e7d7434b5dc8..5da281a5ebc3 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -860,7 +860,7 @@ class StorageManagerService extends IStorageManager.Stub
} else if (remote == 1) {
res = true;
} else {
- res = false;
+ res = true;
}
Slog.d(TAG, "Isolated storage local flag " + local + " and remote flag "
@@ -1533,7 +1533,7 @@ class StorageManagerService extends IStorageManager.Stub
// Snapshot feature flag used for this boot
SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT, Boolean.toString(
- SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, false)));
+ SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, true)));
mContext = context;
mResolver = mContext.getContentResolver();
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 2f1510e32311..81209763d3a8 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -26,6 +26,7 @@ import android.content.pm.PackageManager;
import android.net.LinkProperties;
import android.net.NetworkCapabilities;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -246,7 +247,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
private PreciseDataConnectionState mPreciseDataConnectionState =
new PreciseDataConnectionState();
- static final int ENFORCE_COARSE_LOCATION_PERMISSION_MASK =
+ // Nothing here yet, but putting it here in case we want to add more in the future.
+ static final int ENFORCE_COARSE_LOCATION_PERMISSION_MASK = 0;
+
+ static final int ENFORCE_FINE_LOCATION_PERMISSION_MASK =
PhoneStateListener.LISTEN_CELL_LOCATION
| PhoneStateListener.LISTEN_CELL_INFO;
@@ -637,8 +641,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
try {
if (VDBG) log("listen: call onSSC state=" + mServiceState[phoneId]);
- r.callback.onServiceStateChanged(
- new ServiceState(mServiceState[phoneId]));
+ ServiceState rawSs = new ServiceState(mServiceState[phoneId]);
+ if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ r.callback.onServiceStateChanged(rawSs);
+ } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) {
+ r.callback.onServiceStateChanged(rawSs.sanitizeLocationInfo(false));
+ } else {
+ r.callback.onServiceStateChanged(rawSs.sanitizeLocationInfo(true));
+ }
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -673,7 +683,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
try {
if (DBG_LOC) log("listen: mCellLocation = "
+ mCellLocation[phoneId]);
- if (checkLocationAccess(r)) {
+ if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
r.callback.onCellLocationChanged(
new Bundle(mCellLocation[phoneId]));
}
@@ -722,7 +732,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
try {
if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
+ mCellInfo.get(phoneId));
- if (checkLocationAccess(r)) {
+ if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
}
} catch (RemoteException ex) {
@@ -1009,13 +1019,22 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SERVICE_STATE) &&
idMatch(r.subId, subId, phoneId)) {
+
try {
+ ServiceState stateToSend;
+ if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ stateToSend = new ServiceState(state);
+ } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) {
+ stateToSend = state.sanitizeLocationInfo(false);
+ } else {
+ stateToSend = state.sanitizeLocationInfo(true);
+ }
if (DBG) {
log("notifyServiceStateForSubscriber: callback.onSSC r=" + r
+ " subId=" + subId + " phoneId=" + phoneId
+ " state=" + state);
}
- r.callback.onServiceStateChanged(new ServiceState(state));
+ r.callback.onServiceStateChanged(stateToSend);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
@@ -1198,7 +1217,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
for (Record r : mRecords) {
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) &&
idMatch(r.subId, subId, phoneId) &&
- checkLocationAccess(r)) {
+ checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
try {
if (DBG_LOC) {
log("notifyCellInfo: mCellInfo=" + cellInfo + " r=" + r);
@@ -1500,7 +1519,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
for (Record r : mRecords) {
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) &&
idMatch(r.subId, subId, phoneId) &&
- checkLocationAccess(r)) {
+ checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
try {
if (DBG_LOC) {
log("notifyCellLocation: cellLocation=" + cellLocation
@@ -2108,12 +2127,35 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
private boolean checkListenerPermission(
int events, int subId, String callingPackage, String message) {
+ LocationAccessPolicy.LocationPermissionQuery.Builder locationQueryBuilder =
+ new LocationAccessPolicy.LocationPermissionQuery.Builder()
+ .setCallingPackage(callingPackage)
+ .setMethod(message + " events: " + events)
+ .setCallingPid(Binder.getCallingPid())
+ .setCallingUid(Binder.getCallingUid());
+
+ boolean shouldCheckLocationPermissions = false;
if ((events & ENFORCE_COARSE_LOCATION_PERMISSION_MASK) != 0) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
- if (mAppOps.noteOp(AppOpsManager.OP_COARSE_LOCATION, Binder.getCallingUid(),
- callingPackage) != AppOpsManager.MODE_ALLOWED) {
- return false;
+ locationQueryBuilder.setMinSdkVersionForCoarse(0);
+ shouldCheckLocationPermissions = true;
+ }
+
+ if ((events & ENFORCE_FINE_LOCATION_PERMISSION_MASK) != 0) {
+ // Everything that requires fine location started in Q. So far...
+ locationQueryBuilder.setMinSdkVersionForFine(Build.VERSION_CODES.Q);
+ shouldCheckLocationPermissions = true;
+ }
+
+ if (shouldCheckLocationPermissions) {
+ LocationAccessPolicy.LocationPermissionResult result =
+ LocationAccessPolicy.checkLocationPermission(
+ mContext, locationQueryBuilder.build());
+ switch (result) {
+ case DENIED_HARD:
+ throw new SecurityException("Unable to listen for events " + events + " due to "
+ + "insufficient location permissions.");
+ case DENIED_SOFT:
+ return false;
}
}
@@ -2228,15 +2270,38 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- private boolean checkLocationAccess(Record r) {
- long token = Binder.clearCallingIdentity();
- try {
- return LocationAccessPolicy.canAccessCellLocation(mContext,
- r.callingPackage, r.callerUid, r.callerPid,
- /*throwOnDeniedPermission*/ false);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ private boolean checkFineLocationAccess(Record r, int minSdk) {
+ LocationAccessPolicy.LocationPermissionQuery query =
+ new LocationAccessPolicy.LocationPermissionQuery.Builder()
+ .setCallingPackage(r.callingPackage)
+ .setCallingPid(r.callerPid)
+ .setCallingUid(r.callerUid)
+ .setMethod("TelephonyRegistry push")
+ .setMinSdkVersionForFine(minSdk)
+ .build();
+
+ return Binder.withCleanCallingIdentity(() -> {
+ LocationAccessPolicy.LocationPermissionResult locationResult =
+ LocationAccessPolicy.checkLocationPermission(mContext, query);
+ return locationResult == LocationAccessPolicy.LocationPermissionResult.ALLOWED;
+ });
+ }
+
+ private boolean checkCoarseLocationAccess(Record r, int minSdk) {
+ LocationAccessPolicy.LocationPermissionQuery query =
+ new LocationAccessPolicy.LocationPermissionQuery.Builder()
+ .setCallingPackage(r.callingPackage)
+ .setCallingPid(r.callerPid)
+ .setCallingUid(r.callerUid)
+ .setMethod("TelephonyRegistry push")
+ .setMinSdkVersionForCoarse(minSdk)
+ .build();
+
+ return Binder.withCleanCallingIdentity(() -> {
+ LocationAccessPolicy.LocationPermissionResult locationResult =
+ LocationAccessPolicy.checkLocationPermission(mContext, query);
+ return locationResult == LocationAccessPolicy.LocationPermissionResult.ALLOWED;
+ });
}
private void checkPossibleMissNotify(Record r, int phoneId) {
@@ -2286,7 +2351,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = "
+ mCellInfo.get(phoneId));
}
- if (checkLocationAccess(r)) {
+ if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
}
} catch (RemoteException ex) {
@@ -2336,7 +2401,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
try {
if (DBG_LOC) log("checkPossibleMissNotify: onCellLocationChanged mCellLocation = "
+ mCellLocation[phoneId]);
- if (checkLocationAccess(r)) {
+ if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
r.callback.onCellLocationChanged(new Bundle(mCellLocation[phoneId]));
}
} catch (RemoteException ex) {
diff --git a/services/core/java/com/android/server/WiredAccessoryManager.java b/services/core/java/com/android/server/WiredAccessoryManager.java
index 3939bee52aa2..9bbc3158757c 100644
--- a/services/core/java/com/android/server/WiredAccessoryManager.java
+++ b/services/core/java/com/android/server/WiredAccessoryManager.java
@@ -23,6 +23,7 @@ import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.UEventObserver;
+import android.util.Pair;
import android.util.Slog;
import android.media.AudioManager;
import android.util.Log;
@@ -31,6 +32,7 @@ import android.view.InputDevice;
import com.android.internal.R;
import com.android.server.input.InputManagerService;
import com.android.server.input.InputManagerService.WiredAccessoryCallbacks;
+
import static com.android.server.input.InputManagerService.SW_HEADPHONE_INSERT;
import static com.android.server.input.InputManagerService.SW_MICROPHONE_INSERT;
import static com.android.server.input.InputManagerService.SW_LINEOUT_INSERT;
@@ -41,6 +43,7 @@ import static com.android.server.input.InputManagerService.SW_LINEOUT_INSERT_BIT
import java.io.File;
import java.io.FileReader;
import java.io.FileNotFoundException;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -52,7 +55,7 @@ import java.util.Locale;
*/
final class WiredAccessoryManager implements WiredAccessoryCallbacks {
private static final String TAG = WiredAccessoryManager.class.getSimpleName();
- private static final boolean LOG = true;
+ private static final boolean LOG = false;
private static final int BIT_HEADSET = (1 << 0);
private static final int BIT_HEADSET_NO_MIC = (1 << 1);
@@ -60,9 +63,9 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
private static final int BIT_USB_HEADSET_DGTL = (1 << 3);
private static final int BIT_HDMI_AUDIO = (1 << 4);
private static final int BIT_LINEOUT = (1 << 5);
- private static final int SUPPORTED_HEADSETS = (BIT_HEADSET|BIT_HEADSET_NO_MIC|
- BIT_USB_HEADSET_ANLG|BIT_USB_HEADSET_DGTL|
- BIT_HDMI_AUDIO|BIT_LINEOUT);
+ private static final int SUPPORTED_HEADSETS = (BIT_HEADSET | BIT_HEADSET_NO_MIC |
+ BIT_USB_HEADSET_ANLG | BIT_USB_HEADSET_DGTL |
+ BIT_HDMI_AUDIO | BIT_LINEOUT);
private static final String NAME_H2W = "h2w";
private static final String NAME_USB_AUDIO = "usb_audio";
@@ -82,30 +85,34 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
private int mSwitchValues;
private final WiredAccessoryObserver mObserver;
+ private final WiredAccessoryExtconObserver mExtconObserver;
private final InputManagerService mInputManager;
private final boolean mUseDevInputEventForAudioJack;
public WiredAccessoryManager(Context context, InputManagerService inputManager) {
- PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+ PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryManager");
mWakeLock.setReferenceCounted(false);
- mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
+ mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mInputManager = inputManager;
mUseDevInputEventForAudioJack =
context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
+ mExtconObserver = new WiredAccessoryExtconObserver();
mObserver = new WiredAccessoryObserver();
}
private void onSystemReady() {
if (mUseDevInputEventForAudioJack) {
int switchValues = 0;
- if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_HEADPHONE_INSERT) == 1) {
+ if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_HEADPHONE_INSERT)
+ == 1) {
switchValues |= SW_HEADPHONE_INSERT_BIT;
}
- if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MICROPHONE_INSERT) == 1) {
+ if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MICROPHONE_INSERT)
+ == 1) {
switchValues |= SW_MICROPHONE_INSERT_BIT;
}
if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_LINEOUT_INSERT) == 1) {
@@ -115,20 +122,31 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_LINEOUT_INSERT_BIT);
}
- mObserver.init();
+
+ if (ExtconUEventObserver.extconExists()) {
+ if (mUseDevInputEventForAudioJack) {
+ Log.w(TAG, "Both input event and extcon are used for audio jack,"
+ + " please just choose one.");
+ }
+ mExtconObserver.init();
+ } else {
+ mObserver.init();
+ }
}
@Override
public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask) {
- if (LOG) Slog.v(TAG, "notifyWiredAccessoryChanged: when=" + whenNanos
- + " bits=" + switchCodeToString(switchValues, switchMask)
- + " mask=" + Integer.toHexString(switchMask));
+ if (LOG) {
+ Slog.v(TAG, "notifyWiredAccessoryChanged: when=" + whenNanos
+ + " bits=" + switchCodeToString(switchValues, switchMask)
+ + " mask=" + Integer.toHexString(switchMask));
+ }
synchronized (mLock) {
int headset;
mSwitchValues = (mSwitchValues & ~switchMask) | switchValues;
switch (mSwitchValues &
- (SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_LINEOUT_INSERT_BIT)) {
+ (SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_LINEOUT_INSERT_BIT)) {
case 0:
headset = 0;
break;
@@ -155,7 +173,7 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
}
updateLocked(NAME_H2W,
- (mHeadsetState & ~(BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT)) | headset);
+ (mHeadsetState & ~(BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT)) | headset);
}
}
@@ -175,7 +193,7 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
* results in support for the last one plugged in. Similarly, unplugging either is seen as
* unplugging all.
*
- * @param newName One of the NAME_xxx variables defined above.
+ * @param newName One of the NAME_xxx variables defined above.
* @param newState 0 or one of the BIT_xxx variables defined above.
*/
private void updateLocked(String newName, int newState) {
@@ -186,10 +204,12 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT);
boolean h2wStateChange = true;
boolean usbStateChange = true;
- if (LOG) Slog.v(TAG, "newName=" + newName
- + " newState=" + newState
- + " headsetState=" + headsetState
- + " prev headsetState=" + mHeadsetState);
+ if (LOG) {
+ Slog.v(TAG, "newName=" + newName
+ + " newState=" + newState
+ + " headsetState=" + headsetState
+ + " prev headsetState=" + mHeadsetState);
+ }
if (mHeadsetState == headsetState) {
Log.e(TAG, "No state change.");
@@ -229,7 +249,7 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_NEW_DEVICE_STATE:
- setDevicesState(msg.arg1, msg.arg2, (String)msg.obj);
+ setDevicesState(msg.arg1, msg.arg2, (String) msg.obj);
mWakeLock.release();
break;
case MSG_SYSTEM_READY:
@@ -269,9 +289,9 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
if (headset == BIT_HEADSET) {
outDevice = AudioManager.DEVICE_OUT_WIRED_HEADSET;
inDevice = AudioManager.DEVICE_IN_WIRED_HEADSET;
- } else if (headset == BIT_HEADSET_NO_MIC){
+ } else if (headset == BIT_HEADSET_NO_MIC) {
outDevice = AudioManager.DEVICE_OUT_WIRED_HEADPHONE;
- } else if (headset == BIT_LINEOUT){
+ } else if (headset == BIT_LINEOUT) {
outDevice = AudioManager.DEVICE_OUT_LINE;
} else if (headset == BIT_USB_HEADSET_ANLG) {
outDevice = AudioManager.DEVICE_OUT_ANLG_DOCK_HEADSET;
@@ -280,7 +300,7 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
} else if (headset == BIT_HDMI_AUDIO) {
outDevice = AudioManager.DEVICE_OUT_HDMI;
} else {
- Slog.e(TAG, "setDeviceState() invalid headset type: "+headset);
+ Slog.e(TAG, "setDeviceState() invalid headset type: " + headset);
return;
}
@@ -290,10 +310,10 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
}
if (outDevice != 0) {
- mAudioManager.setWiredDeviceConnectionState(outDevice, state, "", headsetName);
+ mAudioManager.setWiredDeviceConnectionState(outDevice, state, "", headsetName);
}
if (inDevice != 0) {
- mAudioManager.setWiredDeviceConnectionState(inDevice, state, "", headsetName);
+ mAudioManager.setWiredDeviceConnectionState(inDevice, state, "", headsetName);
}
}
}
@@ -340,7 +360,7 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
" not found while attempting to determine initial switch state");
} catch (Exception e) {
Slog.e(TAG, "Error while attempting to determine initial switch state for "
- + uei.getDevName() , e);
+ + uei.getDevName(), e);
}
}
}
@@ -350,7 +370,7 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
// observe three UEVENTs
for (int i = 0; i < mUEventInfo.size(); ++i) {
UEventInfo uei = mUEventInfo.get(i);
- startObserving("DEVPATH="+uei.getDevPath());
+ startObserving("DEVPATH=" + uei.getDevPath());
}
}
@@ -438,7 +458,9 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
mStateNbits = stateNbits;
}
- public String getDevName() { return mDevName; }
+ public String getDevName() {
+ return mDevName;
+ }
public String getDevPath() {
return String.format(Locale.US, "/devices/virtual/switch/%s", mDevName);
@@ -456,11 +478,84 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
public int computeNewHeadsetState(int headsetState, int switchState) {
int preserveMask = ~(mState1Bits | mState2Bits | mStateNbits);
int setBits = ((switchState == 1) ? mState1Bits :
- ((switchState == 2) ? mState2Bits :
- ((switchState == mStateNbits) ? mStateNbits : 0)));
+ ((switchState == 2) ? mState2Bits :
+ ((switchState == mStateNbits) ? mStateNbits : 0)));
return ((headsetState & preserveMask) | setBits);
}
}
}
+
+ private class WiredAccessoryExtconObserver extends ExtconStateObserver<Pair<Integer, Integer>> {
+ private final List<ExtconInfo> mExtconInfos;
+
+ WiredAccessoryExtconObserver() {
+ mExtconInfos = ExtconInfo.getExtconInfos(".*audio.*");
+
+ }
+
+ private void init() {
+ for (ExtconInfo extconInfo : mExtconInfos) {
+ Pair<Integer, Integer> state = null;
+ try {
+ state = parseStateFromFile(extconInfo);
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, extconInfo.getStatePath()
+ + " not found while attempting to determine initial state", e);
+ } catch (IOException e) {
+ Slog.e(
+ TAG,
+ "Error reading " + extconInfo.getStatePath()
+ + " while attempting to determine initial state",
+ e);
+ }
+ if (state != null) {
+ updateState(extconInfo, extconInfo.getName(), state);
+ }
+ if (LOG) Slog.d(TAG, "observing " + extconInfo.getName());
+ startObserving(extconInfo);
+ }
+
+ }
+
+ @Override
+ public Pair<Integer, Integer> parseState(ExtconInfo extconInfo, String status) {
+ if (LOG) Slog.v(TAG, "status " + status);
+ int []maskAndState = {0,0};
+ // extcon event state changes from kernel4.9
+ // new state will be like STATE=MICROPHONE=1\nHEADPHONE=0
+ updateBit(maskAndState, BIT_HEADSET_NO_MIC, status, "HEADPHONE") ;
+ updateBit(maskAndState, BIT_HEADSET, status,"MICROPHONE") ;
+ updateBit(maskAndState, BIT_HDMI_AUDIO, status,"HDMI") ;
+ updateBit(maskAndState, BIT_LINEOUT, status,"LINE-OUT") ;
+ if (LOG) Slog.v(TAG, "mask " + maskAndState[0] + " state " + maskAndState[1]);
+ return Pair.create(maskAndState[0],maskAndState[1]);
+ }
+
+ @Override
+ public void updateState(ExtconInfo extconInfo, String name,
+ Pair<Integer, Integer> maskAndState) {
+ synchronized (mLock) {
+ int mask = maskAndState.first;
+ int state = maskAndState.second;
+ updateLocked(name, mHeadsetState | (mask & state) & ~(mask & ~state));
+ return;
+ }
+ }
+ }
+
+ /**
+ * Updates the mask bit at {@code position} to 1 and the state bit at {@code position} to true
+ * if {@code name=1} or false if {}@code name=0} is contained in {@code state}.
+ */
+ private static void updateBit(int[] maskAndState, int position, String state, String name) {
+ maskAndState[0] |= position;
+ if (state.contains(name + "=1")) {
+ maskAndState[0] |= position;
+ maskAndState[1] |= position;
+ } else if (state.contains(name + "=0")) {
+ maskAndState[0] |= position;
+ maskAndState[1] &= ~position;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index c7b9a3cb7847..8ccb6e20a614 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -82,6 +82,9 @@ public class AdbDebuggingManager {
private static final String ADB_DIRECTORY = "misc/adb";
// This file contains keys that will always be allowed to connect to the device via adb.
private static final String ADB_KEYS_FILE = "adb_keys";
+ // This file contains keys that will be allowed to connect without user interaction as long
+ // as a subsequent connection occurs within the allowed duration.
+ private static final String ADB_TEMP_KEYS_FILE = "adb_temp_keys.xml";
private static final int BUFFER_SIZE = 4096;
private final Context mContext;
@@ -263,7 +266,6 @@ public class AdbDebuggingManager {
AdbDebuggingHandler(Looper looper) {
super(looper);
- mAdbKeyStore = new AdbKeyStore();
}
/**
@@ -289,6 +291,7 @@ public class AdbDebuggingManager {
mThread = new AdbDebuggingThread();
mThread.start();
+ mAdbKeyStore = new AdbKeyStore();
break;
case MESSAGE_ADB_DISABLED:
@@ -303,6 +306,9 @@ public class AdbDebuggingManager {
mThread = null;
}
+ cancelJobToUpdateAdbKeyStore();
+ mAdbKeyStore = null;
+ mConnectedKey = null;
break;
case MESSAGE_ADB_ALLOW: {
@@ -322,6 +328,9 @@ public class AdbDebuggingManager {
mConnectedKey = key;
mAdbKeyStore.setLastConnectionTime(key, System.currentTimeMillis());
scheduleJobToUpdateAdbKeyStore();
+ // write this key to adb_keys as well so that subsequent connections can
+ // go through the expected SIGNATURE interaction.
+ writeKey(key);
}
logAdbConnectionChanged(key, AdbProtoEnums.USER_ALLOWED, alwaysAllow);
}
@@ -354,20 +363,9 @@ public class AdbDebuggingManager {
}
break;
}
- // Check if the key should be allowed without user interaction.
- if (mAdbKeyStore.isKeyAuthorized(key)) {
- if (mThread != null) {
- mThread.sendResponse("OK");
- mAdbKeyStore.setLastConnectionTime(key, System.currentTimeMillis());
- logAdbConnectionChanged(key, AdbProtoEnums.AUTOMATICALLY_ALLOWED, true);
- mConnectedKey = key;
- scheduleJobToUpdateAdbKeyStore();
- }
- } else {
- logAdbConnectionChanged(key, AdbProtoEnums.AWAITING_USER_APPROVAL, false);
- mFingerprints = fingerprints;
- startConfirmation(key, mFingerprints);
- }
+ logAdbConnectionChanged(key, AdbProtoEnums.AWAITING_USER_APPROVAL, false);
+ mFingerprints = fingerprints;
+ startConfirmation(key, mFingerprints);
break;
}
@@ -532,7 +530,11 @@ public class AdbDebuggingManager {
return new File(adbDir, fileName);
}
- private File getUserKeyFile() {
+ File getAdbTempKeysFile() {
+ return getAdbFile(ADB_TEMP_KEYS_FILE);
+ }
+
+ File getUserKeyFile() {
return getAdbFile(ADB_KEYS_FILE);
}
@@ -668,9 +670,6 @@ public class AdbDebuggingManager {
private Map<String, Long> mKeyMap;
private File mKeyFile;
private AtomicFile mAtomicKeyFile;
- // This file contains keys that will be allowed to connect without user interaction as long
- // as a subsequent connection occurs within the allowed duration.
- private static final String ADB_TEMP_KEYS_FILE = "adb_temp_keys.xml";
private static final String XML_TAG_ADB_KEY = "adbKey";
private static final String XML_ATTRIBUTE_KEY = "key";
private static final String XML_ATTRIBUTE_LAST_CONNECTION = "lastConnection";
@@ -704,9 +703,9 @@ public class AdbDebuggingManager {
*/
private void initKeyFile() {
if (mKeyFile == null) {
- mKeyFile = getAdbFile(ADB_TEMP_KEYS_FILE);
+ mKeyFile = getAdbTempKeysFile();
}
- // getAdbFile can return null if the adb file cannot be obtained
+ // getAdbTempKeysFile can return null if the adb file cannot be obtained
if (mKeyFile != null) {
mAtomicKeyFile = new AtomicFile(mKeyFile);
}
@@ -767,7 +766,8 @@ public class AdbDebuggingManager {
public void persistKeyStore() {
// if there is nothing in the key map then ensure any keys left in the key store files
// are deleted as well.
- if (mKeyMap.size() == 0) {
+ filterOutOldKeys();
+ if (mKeyMap.isEmpty()) {
deleteKeyStore();
return;
}
@@ -784,22 +784,15 @@ public class AdbDebuggingManager {
keyStream = mAtomicKeyFile.startWrite();
serializer.setOutput(keyStream, StandardCharsets.UTF_8.name());
serializer.startDocument(null, true);
- long allowedTime = getAllowedConnectionTime();
- long systemTime = System.currentTimeMillis();
- Iterator keyMapIterator = mKeyMap.entrySet().iterator();
- while (keyMapIterator.hasNext()) {
- Map.Entry<String, Long> keyEntry = (Map.Entry) keyMapIterator.next();
- long connectionTime = keyEntry.getValue();
- if (systemTime < (connectionTime + allowedTime)) {
- serializer.startTag(null, XML_TAG_ADB_KEY);
- serializer.attribute(null, XML_ATTRIBUTE_KEY, keyEntry.getKey());
- serializer.attribute(null, XML_ATTRIBUTE_LAST_CONNECTION,
- String.valueOf(keyEntry.getValue()));
- serializer.endTag(null, XML_TAG_ADB_KEY);
- } else {
- keyMapIterator.remove();
- }
+
+ for (Map.Entry<String, Long> keyEntry : mKeyMap.entrySet()) {
+ serializer.startTag(null, XML_TAG_ADB_KEY);
+ serializer.attribute(null, XML_ATTRIBUTE_KEY, keyEntry.getKey());
+ serializer.attribute(null, XML_ATTRIBUTE_LAST_CONNECTION,
+ String.valueOf(keyEntry.getValue()));
+ serializer.endTag(null, XML_TAG_ADB_KEY);
}
+
serializer.endDocument();
mAtomicKeyFile.finishWrite(keyStream);
} catch (IOException e) {
@@ -808,6 +801,19 @@ public class AdbDebuggingManager {
}
}
+ private void filterOutOldKeys() {
+ long allowedTime = getAllowedConnectionTime();
+ long systemTime = System.currentTimeMillis();
+ Iterator<Map.Entry<String, Long>> keyMapIterator = mKeyMap.entrySet().iterator();
+ while (keyMapIterator.hasNext()) {
+ Map.Entry<String, Long> keyEntry = keyMapIterator.next();
+ long connectionTime = keyEntry.getValue();
+ if (allowedTime != 0 && systemTime > (connectionTime + allowedTime)) {
+ keyMapIterator.remove();
+ }
+ }
+ }
+
/**
* Removes all of the entries in the key map and deletes the key file.
*/
diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java
index c31691551269..7fd98e0043c9 100644
--- a/services/core/java/com/android/server/adb/AdbService.java
+++ b/services/core/java/com/android/server/adb/AdbService.java
@@ -45,6 +45,7 @@ import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Collections;
@@ -95,6 +96,16 @@ public class AdbService extends IAdbManager.Stub {
public boolean isAdbEnabled() {
return mAdbEnabled;
}
+
+ @Override
+ public File getAdbKeysFile() {
+ return mDebuggingManager.getUserKeyFile();
+ }
+
+ @Override
+ public File getAdbTempKeysFile() {
+ return mDebuggingManager.getAdbTempKeysFile();
+ }
}
private final class AdbHandler extends Handler {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 60a45bfe04bb..2f20572caa99 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6630,8 +6630,7 @@ public class ActivityManagerService extends IActivityManager.Stub
String msg;
if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
- throw new SecurityException("Content provider lookup "
- + cpr.name.flattenToShortString()
+ throw new SecurityException("Content provider lookup " + name
+ " failed: association not allowed with package " + msg);
}
checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
@@ -18101,8 +18100,10 @@ public class ActivityManagerService extends IActivityManager.Stub
if (!queue.isIdle()) {
final String msg = "Waiting for queue " + queue + " to become idle...";
pw.println(msg);
+ pw.println(queue.describeState());
pw.flush();
Slog.v(TAG, msg);
+ queue.cancelDeferrals();
idle = false;
}
}
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 24543b7974df..236797b57556 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -477,6 +477,10 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
mStats.updateRpmStatsLocked();
}
+ if ((updateFlags & UPDATE_RAIL) != 0) {
+ mStats.updateRailStatsLocked();
+ }
+
if (bluetoothInfo != null) {
if (bluetoothInfo.isValid()) {
mStats.updateBluetoothStateLocked(bluetoothInfo);
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 08900328a200..4d5cb8cb4473 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -59,6 +59,7 @@ import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BatteryStatsHelper;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.PowerProfile;
+import com.android.internal.os.RailStats;
import com.android.internal.os.RpmStats;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.ParseUtils;
@@ -84,7 +85,8 @@ import java.util.concurrent.Future;
*/
public final class BatteryStatsService extends IBatteryStats.Stub
implements PowerManagerInternal.LowPowerModeListener,
- BatteryStatsImpl.PlatformIdleStateCallback {
+ BatteryStatsImpl.PlatformIdleStateCallback,
+ BatteryStatsImpl.RailEnergyDataCallback {
static final String TAG = "BatteryStatsService";
static final boolean DBG = false;
@@ -98,6 +100,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
private native void getLowPowerStats(RpmStats rpmStats);
private native int getPlatformLowPowerStats(ByteBuffer outBuffer);
private native int getSubsystemLowPowerStats(ByteBuffer outBuffer);
+ private native void getRailEnergyPowerStats(RailStats railStats);
private CharsetDecoder mDecoderStat = StandardCharsets.UTF_8
.newDecoder()
.onMalformedInput(CodingErrorAction.REPLACE)
@@ -121,6 +124,16 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
@Override
+ public void fillRailDataStats(RailStats railStats) {
+ if (DBG) Slog.d(TAG, "begin getRailEnergyPowerStats");
+ try {
+ getRailEnergyPowerStats(railStats);
+ } finally {
+ if (DBG) Slog.d(TAG, "end getRailEnergyPowerStats");
+ }
+ }
+
+ @Override
public String getPlatformLowPowerStats() {
if (DBG) Slog.d(TAG, "begin getPlatformLowPowerStats");
try {
@@ -177,7 +190,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub
return (umi != null) ? umi.getUserIds() : null;
}
};
- mStats = new BatteryStatsImpl(systemDir, handler, this, mUserManagerUserInfoProvider);
+ mStats = new BatteryStatsImpl(systemDir, handler, this,
+ this, mUserManagerUserInfoProvider);
mWorker = new BatteryExternalStatsWorker(context, mStats);
mStats.setExternalStatsSyncLocked(mWorker);
mStats.setRadioScanningTimeoutLocked(mContext.getResources().getInteger(
@@ -1460,7 +1474,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub
in.unmarshall(raw, 0, raw.length);
in.setDataPosition(0);
BatteryStatsImpl checkinStats = new BatteryStatsImpl(
- null, mStats.mHandler, null, mUserManagerUserInfoProvider);
+ null, mStats.mHandler, null, null,
+ mUserManagerUserInfoProvider);
checkinStats.readSummaryFromParcel(in);
in.recycle();
checkinStats.dumpProtoLocked(
@@ -1498,7 +1513,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub
in.unmarshall(raw, 0, raw.length);
in.setDataPosition(0);
BatteryStatsImpl checkinStats = new BatteryStatsImpl(
- null, mStats.mHandler, null, mUserManagerUserInfoProvider);
+ null, mStats.mHandler, null, null,
+ mUserManagerUserInfoProvider);
checkinStats.readSummaryFromParcel(in);
in.recycle();
checkinStats.dumpCheckinLocked(mContext, pw, apps, flags,
diff --git a/services/core/java/com/android/server/am/BroadcastDispatcher.java b/services/core/java/com/android/server/am/BroadcastDispatcher.java
index 6371cd376d19..0b38ef94de1e 100644
--- a/services/core/java/com/android/server/am/BroadcastDispatcher.java
+++ b/services/core/java/com/android/server/am/BroadcastDispatcher.java
@@ -65,6 +65,14 @@ public class BroadcastDispatcher {
broadcasts.add(br);
}
+ int size() {
+ return broadcasts.size();
+ }
+
+ boolean isEmpty() {
+ return broadcasts.isEmpty();
+ }
+
void writeToProto(ProtoOutputStream proto, long fieldId) {
for (BroadcastRecord br : broadcasts) {
br.writeToProto(proto, fieldId);
@@ -252,22 +260,48 @@ public class BroadcastDispatcher {
synchronized (mLock) {
return mCurrentBroadcast == null
&& mOrderedBroadcasts.isEmpty()
- && mDeferredBroadcasts.isEmpty()
- && mAlarmBroadcasts.isEmpty();
+ && isDeferralsListEmpty(mDeferredBroadcasts)
+ && isDeferralsListEmpty(mAlarmBroadcasts);
+ }
+ }
+
+ private static int pendingInDeferralsList(ArrayList<Deferrals> list) {
+ int pending = 0;
+ final int numEntries = list.size();
+ for (int i = 0; i < numEntries; i++) {
+ pending += list.get(i).size();
}
+ return pending;
+ }
+
+ private static boolean isDeferralsListEmpty(ArrayList<Deferrals> list) {
+ return pendingInDeferralsList(list) == 0;
}
/**
- * Not quite the traditional size() measurement; includes any in-process but
- * not yet retired active outbound broadcast.
+ * Strictly for logging, describe the currently pending contents in a human-
+ * readable way
*/
- public int totalUndelivered() {
- synchronized (mLock) {
- return mAlarmBroadcasts.size()
- + mDeferredBroadcasts.size()
- + mOrderedBroadcasts.size()
- + (mCurrentBroadcast == null ? 0 : 1);
- }
+ public String describeStateLocked() {
+ final StringBuilder sb = new StringBuilder(128);
+ if (mCurrentBroadcast != null) {
+ sb.append("1 in flight, ");
+ }
+ sb.append(mOrderedBroadcasts.size());
+ sb.append(" ordered");
+ int n = pendingInDeferralsList(mAlarmBroadcasts);
+ if (n > 0) {
+ sb.append(", ");
+ sb.append(n);
+ sb.append(" deferrals in alarm recipients");
+ }
+ n = pendingInDeferralsList(mDeferredBroadcasts);
+ if (n > 0) {
+ sb.append(", ");
+ sb.append(n);
+ sb.append(" deferred");
+ }
+ return sb.toString();
}
// ----------------------------------
@@ -579,6 +613,26 @@ public class BroadcastDispatcher {
}
}
+ /**
+ * Cancel all current deferrals; that is, make all currently-deferred broadcasts
+ * immediately deliverable. Used by the wait-for-broadcast-idle mechanism.
+ */
+ public void cancelDeferrals() {
+ synchronized (mLock) {
+ zeroDeferralTimes(mAlarmBroadcasts);
+ zeroDeferralTimes(mDeferredBroadcasts);
+ }
+ }
+
+ private static void zeroDeferralTimes(ArrayList<Deferrals> list) {
+ final int num = list.size();
+ for (int i = 0; i < num; i++) {
+ Deferrals d = list.get(i);
+ // Safe to do this in-place because it won't break ordering
+ d.deferUntil = d.deferredBy = 0;
+ }
+ }
+
// ----------------------------------
/**
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index f0b137a6ccb1..d9ea1da79f56 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -898,6 +898,11 @@ public final class BroadcastQueue {
for (int i = perms.length-1; i >= 0; i--) {
try {
PermissionInfo pi = pm.getPermissionInfo(perms[i], "android", 0);
+ if (pi == null) {
+ // a required permission that no package has actually
+ // defined cannot be signature-required.
+ return false;
+ }
if ((pi.protectionLevel & (PermissionInfo.PROTECTION_MASK_BASE
| PermissionInfo.PROTECTION_FLAG_PRIVILEGED))
!= PermissionInfo.PROTECTION_SIGNATURE) {
@@ -923,8 +928,8 @@ public final class BroadcastQueue {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast ["
+ mQueueName + "]: "
- + mParallelBroadcasts.size() + " parallel broadcasts, "
- + mDispatcher.totalUndelivered() + " ordered broadcasts");
+ + mParallelBroadcasts.size() + " parallel broadcasts; "
+ + mDispatcher.describeStateLocked());
mService.updateCpuStats();
@@ -1822,11 +1827,24 @@ public final class BroadcastQueue {
record.intent == null ? "" : record.intent.getAction());
}
- final boolean isIdle() {
+ boolean isIdle() {
return mParallelBroadcasts.isEmpty() && mDispatcher.isEmpty()
&& (mPendingBroadcast == null);
}
+ // Used by wait-for-broadcast-idle : fast-forward all current deferrals to
+ // be immediately deliverable.
+ void cancelDeferrals() {
+ mDispatcher.cancelDeferrals();
+ }
+
+ String describeState() {
+ synchronized (mService) {
+ return mParallelBroadcasts.size() + " parallel; "
+ + mDispatcher.describeStateLocked();
+ }
+ }
+
void writeToProto(ProtoOutputStream proto, long fieldId) {
long token = proto.start(fieldId);
proto.write(BroadcastQueueProto.QUEUE_NAME, mQueueName);
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 01946247bd12..8ffb67a1405c 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -65,6 +65,8 @@ final class CoreSettingsObserver extends ContentObserver {
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES, String.class);
sGlobalSettingToTypeMap.put(
Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST, String.class);
+ sGlobalSettingToTypeMap.put(
+ Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, int.class);
sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_APP, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS, String.class);
@@ -76,6 +78,7 @@ final class CoreSettingsObserver extends ContentObserver {
sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_OPT_OUT_APPS, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_BLACKLIST, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_WHITELIST, String.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_BLACKLISTS, String.class);
// add other global settings here...
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index f01305eab761..0d49e4cdc9d0 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1681,7 +1681,8 @@ public final class ProcessList {
public void killAppZygoteIfNeededLocked(AppZygote appZygote) {
final ApplicationInfo appInfo = appZygote.getAppInfo();
ArrayList<ProcessRecord> zygoteProcesses = mAppZygoteProcesses.get(appZygote);
- if (zygoteProcesses.size() == 0) { // Only remove if no longer in use now
+ if (zygoteProcesses != null && zygoteProcesses.size() == 0) {
+ // Only remove if no longer in use now
mAppZygotes.remove(appInfo.processName, appInfo.uid);
mAppZygoteProcesses.remove(appZygote);
mAppIsolatedUidRangeAllocator.freeUidRangeLocked(appInfo);
@@ -1703,6 +1704,7 @@ public final class ProcessList {
ArrayList<ProcessRecord> zygoteProcesses = mAppZygoteProcesses.get(appZygote);
zygoteProcesses.remove(app);
if (zygoteProcesses.size() == 0) {
+ mService.mHandler.removeMessages(KILL_APP_ZYGOTE_MSG);
Message msg = mService.mHandler.obtainMessage(KILL_APP_ZYGOTE_MSG);
msg.obj = appZygote;
mService.mHandler.sendMessageDelayed(msg, KILL_APP_ZYGOTE_DELAY_MS);
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index c981e6885a9e..7f6648a3d174 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2072,7 +2072,8 @@ class UserController implements Handler.Callback {
new TimingsTraceLog("SystemServerTiming", Trace.TRACE_TAG_SYSTEM_SERVER)
.logDuration("SystemUserUnlock", unlockTime);
} else {
- Slog.d(TAG, "Unlocking user " + id + " took " + unlockTime + " ms");
+ new TimingsTraceLog("SystemServerTiming", Trace.TRACE_TAG_SYSTEM_SERVER)
+ .logDuration("User" + id + "Unlock", unlockTime);
}
}
};
diff --git a/services/core/java/com/android/server/appbinding/AppBindingService.java b/services/core/java/com/android/server/appbinding/AppBindingService.java
index 0b6a4329d15b..bbe4ed15b3a0 100644
--- a/services/core/java/com/android/server/appbinding/AppBindingService.java
+++ b/services/core/java/com/android/server/appbinding/AppBindingService.java
@@ -177,13 +177,12 @@ public class AppBindingService extends Binder {
* Handle boot phase PHASE_ACTIVITY_MANAGER_READY.
*/
private void onPhaseActivityManagerReady() {
+ // RoleManager doesn't tell us about upgrade, so we still need to listen for app upgrades.
+ // (app uninstall/disable will be notified by RoleManager.)
final IntentFilter packageFilter = new IntentFilter();
packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
packageFilter.addDataScheme("package");
- packageFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiverAsUser(mPackageUserMonitor, UserHandle.ALL,
packageFilter, null, mHandler);
@@ -256,14 +255,6 @@ public class AppBindingService extends Binder {
handlePackageAddedReplacing(packageName, userId);
}
break;
- case Intent.ACTION_PACKAGE_REMOVED:
- if (!replacing) {
- handlePackageRemoved(packageName, userId);
- }
- break;
- case Intent.ACTION_PACKAGE_CHANGED:
- handlePackageChanged(packageName, userId);
- break;
}
}
};
@@ -371,31 +362,6 @@ public class AppBindingService extends Binder {
}
}
- private void handlePackageRemoved(String packageName, int userId) {
- if (DEBUG) {
- Slog.d(TAG, "handlePackageRemoved: u" + userId + " " + packageName);
- }
- synchronized (mLock) {
- final AppServiceFinder finder = findFinderLocked(userId, packageName);
- if (finder != null) {
- unbindServicesLocked(userId, finder, "package uninstall");
- }
- }
- }
-
- private void handlePackageChanged(String packageName, int userId) {
- if (DEBUG) {
- Slog.d(TAG, "handlePackageChanged: u" + userId + " " + packageName);
- }
- synchronized (mLock) {
- final AppServiceFinder finder = findFinderLocked(userId, packageName);
- if (finder != null) {
- unbindServicesLocked(userId, finder, "package changed");
- bindServicesLocked(userId, finder, "package changed");
- }
- }
- }
-
private void rebindAllLocked(String reason) {
for (int i = 0; i < mRunningUsers.size(); i++) {
if (!mRunningUsers.valueAt(i)) {
diff --git a/services/core/java/com/android/server/appbinding/finders/CarrierMessagingClientServiceFinder.java b/services/core/java/com/android/server/appbinding/finders/CarrierMessagingClientServiceFinder.java
index 4c5f1a1c7b49..753d3b0cc10e 100644
--- a/services/core/java/com/android/server/appbinding/finders/CarrierMessagingClientServiceFinder.java
+++ b/services/core/java/com/android/server/appbinding/finders/CarrierMessagingClientServiceFinder.java
@@ -16,14 +16,10 @@
package com.android.server.appbinding.finders;
-import static android.provider.Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL;
-
import android.Manifest.permission;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
+import android.app.role.OnRoleHoldersChangedListener;
+import android.app.role.RoleManager;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.ServiceInfo;
import android.os.Handler;
import android.os.IBinder;
@@ -35,7 +31,8 @@ import android.text.TextUtils;
import android.util.Slog;
import com.android.internal.R;
-import com.android.internal.telephony.SmsApplication;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.CollectionUtils;
import com.android.server.appbinding.AppBindingConstants;
import java.util.function.BiConsumer;
@@ -45,10 +42,15 @@ import java.util.function.BiConsumer;
*/
public class CarrierMessagingClientServiceFinder
extends AppServiceFinder<CarrierMessagingClientService, ICarrierMessagingClientService> {
+
+ private final RoleManager mRoleManager;
+
public CarrierMessagingClientServiceFinder(Context context,
BiConsumer<AppServiceFinder, Integer> listener,
Handler callbackHandler) {
super(context, listener, callbackHandler);
+
+ mRoleManager = context.getSystemService(RoleManager.class);
}
@Override
@@ -84,9 +86,8 @@ public class CarrierMessagingClientServiceFinder
@Override
public String getTargetPackage(int userId) {
- final ComponentName cn = SmsApplication.getDefaultSmsApplicationAsUser(
- mContext, /* updateIfNeeded= */ true, userId);
- String ret = cn == null ? null : cn.getPackageName();
+ final String ret = CollectionUtils.firstOrNull(mRoleManager.getRoleHoldersAsUser(
+ RoleManager.ROLE_SMS, UserHandle.of(userId)));
if (DEBUG) {
Slog.d(TAG, "getTargetPackage()=" + ret);
@@ -97,9 +98,8 @@ public class CarrierMessagingClientServiceFinder
@Override
public void startMonitoring() {
- final IntentFilter filter = new IntentFilter(ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL);
- mContext.registerReceiverAsUser(mSmsAppChangedWatcher, UserHandle.ALL, filter,
- /* permission= */ null, mHandler);
+ mRoleManager.addOnRoleHoldersChangedListenerAsUser(
+ mContext.getMainExecutor(), mRoleHolderChangedListener, UserHandle.ALL);
}
@Override
@@ -118,12 +118,11 @@ public class CarrierMessagingClientServiceFinder
return constants.SMS_APP_BIND_FLAGS;
}
- private final BroadcastReceiver mSmsAppChangedWatcher = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL.equals(intent.getAction())) {
- mListener.accept(CarrierMessagingClientServiceFinder.this, getSendingUserId());
- }
+ private final OnRoleHoldersChangedListener mRoleHolderChangedListener = (role, user) -> {
+ if (RoleManager.ROLE_SMS.equals(role)) {
+ BackgroundThread.getHandler().post(() -> {
+ mListener.accept(CarrierMessagingClientServiceFinder.this, user.getIdentifier());
+ });
}
};
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 0dc73d9278a2..6df60d6bdd3a 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -21,6 +21,8 @@ import static com.android.server.audio.AudioService.CONNECTION_STATE_DISCONNECTE
import android.annotation.NonNull;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothProfile;
import android.content.ContentResolver;
import android.content.Context;
@@ -424,11 +426,28 @@ import java.util.ArrayList;
}
/*package*/ void postDisconnectHearingAid() {
- sendMsgNoDelay(MSG_DISCONNECT_HEARING_AID, SENDMSG_QUEUE);
+ sendMsgNoDelay(MSG_DISCONNECT_BT_HEARING_AID, SENDMSG_QUEUE);
}
/*package*/ void postDisconnectHeadset() {
- sendMsgNoDelay(MSG_DISCONNECT_HEADSET, SENDMSG_QUEUE);
+ sendMsgNoDelay(MSG_DISCONNECT_BT_HEADSET, SENDMSG_QUEUE);
+ }
+
+ /*package*/ void postBtA2dpProfileConnected(BluetoothA2dp a2dpProfile) {
+ sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP, SENDMSG_QUEUE, a2dpProfile);
+ }
+
+ /*package*/ void postBtA2dpSinkProfileConnected(BluetoothProfile profile) {
+ sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK, SENDMSG_QUEUE, profile);
+ }
+
+ /*package*/ void postBtHeasetProfileConnected(BluetoothHeadset headsetProfile) {
+ sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET, SENDMSG_QUEUE, headsetProfile);
+ }
+
+ /*package*/ void postBtHearingAidProfileConnected(BluetoothHearingAid hearingAidProfile) {
+ sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID, SENDMSG_QUEUE,
+ hearingAidProfile);
}
//---------------------------------------------------------------------
@@ -460,16 +479,14 @@ import java.util.ArrayList;
}
}
+ @GuardedBy("mDeviceStateLock")
/*package*/ void handleSetA2dpSinkConnectionState(@BluetoothProfile.BtProfileState int state,
@NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
final int intState = (state == BluetoothA2dp.STATE_CONNECTED)
? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED;
- final int delay;
- synchronized (mDeviceStateLock) {
- delay = mDeviceInventory.checkSendBecomingNoisyIntent(
+ final int delay = mDeviceInventory.checkSendBecomingNoisyIntent(
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, intState,
AudioSystem.DEVICE_NONE);
- }
final String addr = btDeviceInfo == null ? "null" : btDeviceInfo.getBtDevice().getAddress();
if (AudioService.DEBUG_DEVICES) {
@@ -719,16 +736,36 @@ import java.util.ArrayList;
mDeviceInventory.disconnectA2dpSink();
}
break;
- case MSG_DISCONNECT_HEARING_AID:
+ case MSG_DISCONNECT_BT_HEARING_AID:
synchronized (mDeviceStateLock) {
mDeviceInventory.disconnectHearingAid();
}
break;
- case MSG_DISCONNECT_HEADSET:
+ case MSG_DISCONNECT_BT_HEADSET:
synchronized (mDeviceStateLock) {
mBtHelper.disconnectHeadset();
}
break;
+ case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP:
+ synchronized (mDeviceStateLock) {
+ mBtHelper.onA2dpProfileConnected((BluetoothA2dp) msg.obj);
+ }
+ break;
+ case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK:
+ synchronized (mDeviceStateLock) {
+ mBtHelper.onA2dpSinkProfileConnected((BluetoothProfile) msg.obj);
+ }
+ break;
+ case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID:
+ synchronized (mDeviceStateLock) {
+ mBtHelper.onHearingAidProfileConnected((BluetoothHearingAid) msg.obj);
+ }
+ break;
+ case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET:
+ synchronized (mDeviceStateLock) {
+ mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj);
+ }
+ break;
default:
Log.wtf(TAG, "Invalid message " + msg.what);
}
@@ -766,8 +803,12 @@ import java.util.ArrayList;
private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE = 18;
private static final int MSG_DISCONNECT_A2DP = 19;
private static final int MSG_DISCONNECT_A2DP_SINK = 20;
- private static final int MSG_DISCONNECT_HEARING_AID = 21;
- private static final int MSG_DISCONNECT_HEADSET = 22;
+ private static final int MSG_DISCONNECT_BT_HEARING_AID = 21;
+ private static final int MSG_DISCONNECT_BT_HEADSET = 22;
+ private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP = 23;
+ private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK = 24;
+ private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID = 25;
+ private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET = 26;
private static boolean isMessageHandledUnderWakelock(int msgId) {
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index e9189974e988..58c1882abf6f 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -393,6 +393,84 @@ public class BtHelper {
mBluetoothHeadset = null;
}
+ /*package*/ synchronized void onA2dpProfileConnected(BluetoothA2dp a2dp) {
+ mA2dp = a2dp;
+ final List<BluetoothDevice> deviceList = mA2dp.getConnectedDevices();
+ if (deviceList.isEmpty()) {
+ return;
+ }
+ final BluetoothDevice btDevice = deviceList.get(0);
+ final @BluetoothProfile.BtProfileState int state = mA2dp.getConnectionState(btDevice);
+ mDeviceBroker.handleSetA2dpSinkConnectionState(
+ state, new BluetoothA2dpDeviceInfo(btDevice));
+ }
+
+ /*package*/ synchronized void onA2dpSinkProfileConnected(BluetoothProfile profile) {
+ final List<BluetoothDevice> deviceList = profile.getConnectedDevices();
+ if (deviceList.isEmpty()) {
+ return;
+ }
+ final BluetoothDevice btDevice = deviceList.get(0);
+ final @BluetoothProfile.BtProfileState int state =
+ profile.getConnectionState(btDevice);
+ mDeviceBroker.postSetA2dpSourceConnectionState(
+ state, new BluetoothA2dpDeviceInfo(btDevice));
+ }
+
+ /*package*/ synchronized void onHearingAidProfileConnected(BluetoothHearingAid hearingAid) {
+ mHearingAid = hearingAid;
+ final List<BluetoothDevice> deviceList = mHearingAid.getConnectedDevices();
+ if (deviceList.isEmpty()) {
+ return;
+ }
+ final BluetoothDevice btDevice = deviceList.get(0);
+ final @BluetoothProfile.BtProfileState int state =
+ mHearingAid.getConnectionState(btDevice);
+ mDeviceBroker.setBluetoothHearingAidDeviceConnectionState(
+ btDevice, state,
+ /*suppressNoisyIntent*/ false,
+ /*musicDevice*/ android.media.AudioSystem.DEVICE_NONE,
+ /*eventSource*/ "mBluetoothProfileServiceListener");
+ }
+
+ /*package*/ synchronized void onHeadsetProfileConnected(BluetoothHeadset headset) {
+ // Discard timeout message
+ mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService();
+ mBluetoothHeadset = headset;
+ setBtScoActiveDevice(mBluetoothHeadset.getActiveDevice());
+ // Refresh SCO audio state
+ checkScoAudioState();
+ if (mScoAudioState != SCO_STATE_ACTIVATE_REQ
+ && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
+ return;
+ }
+ boolean status = false;
+ if (mBluetoothHeadsetDevice != null) {
+ switch (mScoAudioState) {
+ case SCO_STATE_ACTIVATE_REQ:
+ status = connectBluetoothScoAudioHelper(
+ mBluetoothHeadset,
+ mBluetoothHeadsetDevice, mScoAudioMode);
+ if (status) {
+ mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+ }
+ break;
+ case SCO_STATE_DEACTIVATE_REQ:
+ status = disconnectBluetoothScoAudioHelper(
+ mBluetoothHeadset,
+ mBluetoothHeadsetDevice, mScoAudioMode);
+ if (status) {
+ mScoAudioState = SCO_STATE_DEACTIVATING;
+ }
+ break;
+ }
+ }
+ if (!status) {
+ mScoAudioState = SCO_STATE_INACTIVE;
+ broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+ }
+ }
+
//----------------------------------------------------------------------
private void broadcastScoConnectionState(int state) {
mDeviceBroker.postBroadcastScoConnectionState(state);
@@ -462,99 +540,36 @@ public class BtHelper {
}
}
+ // NOTE this listener is NOT called from AudioDeviceBroker event thread, only call async
+ // methods inside listener.
private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- final BluetoothDevice btDevice;
- List<BluetoothDevice> deviceList;
switch(profile) {
case BluetoothProfile.A2DP:
- synchronized (BtHelper.this) {
- mA2dp = (BluetoothA2dp) proxy;
- deviceList = mA2dp.getConnectedDevices();
- if (deviceList.size() > 0) {
- btDevice = deviceList.get(0);
- if (btDevice == null) {
- Log.e(TAG, "Invalid null device in BT profile listener");
- return;
- }
- final @BluetoothProfile.BtProfileState int state =
- mA2dp.getConnectionState(btDevice);
- mDeviceBroker.handleSetA2dpSinkConnectionState(
- state, new BluetoothA2dpDeviceInfo(btDevice));
- }
- }
+ AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
+ "BT profile service: connecting A2DP profile"));
+ mDeviceBroker.postBtA2dpProfileConnected((BluetoothA2dp) proxy);
break;
case BluetoothProfile.A2DP_SINK:
- deviceList = proxy.getConnectedDevices();
- if (deviceList.size() > 0) {
- btDevice = deviceList.get(0);
- final @BluetoothProfile.BtProfileState int state =
- proxy.getConnectionState(btDevice);
- mDeviceBroker.postSetA2dpSourceConnectionState(
- state, new BluetoothA2dpDeviceInfo(btDevice));
- }
+ AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
+ "BT profile service: connecting A2DP_SINK profile"));
+ mDeviceBroker.postBtA2dpSinkProfileConnected(proxy);
break;
case BluetoothProfile.HEADSET:
- synchronized (BtHelper.this) {
- // Discard timeout message
- mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService();
- mBluetoothHeadset = (BluetoothHeadset) proxy;
- setBtScoActiveDevice(mBluetoothHeadset.getActiveDevice());
- // Refresh SCO audio state
- checkScoAudioState();
- // Continue pending action if any
- if (mScoAudioState == SCO_STATE_ACTIVATE_REQ
- || mScoAudioState == SCO_STATE_DEACTIVATE_REQ) {
- boolean status = false;
- if (mBluetoothHeadsetDevice != null) {
- switch (mScoAudioState) {
- case SCO_STATE_ACTIVATE_REQ:
- status = connectBluetoothScoAudioHelper(
- mBluetoothHeadset,
- mBluetoothHeadsetDevice, mScoAudioMode);
- if (status) {
- mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
- }
- break;
- case SCO_STATE_DEACTIVATE_REQ:
- status = disconnectBluetoothScoAudioHelper(
- mBluetoothHeadset,
- mBluetoothHeadsetDevice, mScoAudioMode);
- if (status) {
- mScoAudioState = SCO_STATE_DEACTIVATING;
- }
- break;
- }
- }
- if (!status) {
- mScoAudioState = SCO_STATE_INACTIVE;
- broadcastScoConnectionState(
- AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
- }
- }
- }
+ AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
+ "BT profile service: connecting HEADSET profile"));
+ mDeviceBroker.postBtHeasetProfileConnected((BluetoothHeadset) proxy);
break;
case BluetoothProfile.HEARING_AID:
- synchronized (BtHelper.this) {
- mHearingAid = (BluetoothHearingAid) proxy;
- deviceList = mHearingAid.getConnectedDevices();
- if (deviceList.size() > 0) {
- btDevice = deviceList.get(0);
- final @BluetoothProfile.BtProfileState int state =
- mHearingAid.getConnectionState(btDevice);
- mDeviceBroker.setBluetoothHearingAidDeviceConnectionState(
- btDevice, state,
- /*suppressNoisyIntent*/ false,
- /*musicDevice*/ android.media.AudioSystem.DEVICE_NONE,
- /*eventSource*/ "mBluetoothProfileServiceListener");
- }
- }
+ AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
+ "BT profile service: connecting HEARING_AID profile"));
+ mDeviceBroker.postBtHearingAidProfileConnected(
+ (BluetoothHearingAid) proxy);
break;
-
default:
break;
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index b50b800f0e20..bca84f7b7217 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -391,10 +391,11 @@ public class BiometricService extends SystemService {
private final Random mRandom = new Random();
// TODO(b/123378871): Remove when moved.
- // When BiometricPrompt#setEnableFallback is set to true, we need to store the client (app)
- // receiver. BiometricService internally launches CDCA which invokes BiometricService to
- // start authentication (normal path). When auth is success/rejected, CDCA will use an aidl
- // method to poke BiometricService - the result will then be forwarded to this receiver.
+ // When BiometricPrompt#setAllowDeviceCredentials is set to true, we need to store the
+ // client (app) receiver. BiometricService internally launches CDCA which invokes
+ // BiometricService to start authentication (normal path). When auth is success/rejected,
+ // CDCA will use an aidl method to poke BiometricService - the result will then be forwarded
+ // to this receiver.
private IBiometricServiceReceiver mConfirmDeviceCredentialReceiver;
// The current authentication session, null if idle/done. We need to track both the current
@@ -803,11 +804,21 @@ public class BiometricService extends SystemService {
// we can't get activity results. Store the receiver somewhere so we can forward the
// result back to the client.
// TODO(b/123378871): Remove when moved.
- if (bundle.getBoolean(BiometricPrompt.KEY_ENABLE_FALLBACK)) {
+ if (bundle.getBoolean(BiometricPrompt.KEY_ALLOW_DEVICE_CREDENTIAL)) {
mHandler.post(() -> {
- mConfirmDeviceCredentialReceiver = receiver;
final KeyguardManager kgm = getContext().getSystemService(
KeyguardManager.class);
+ if (!kgm.isDeviceSecure()) {
+ try {
+ receiver.onError(BiometricConstants.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL,
+ getContext().getString(
+ R.string.biometric_error_device_not_secured));
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ return;
+ }
+ mConfirmDeviceCredentialReceiver = receiver;
// Use this so we don't need to duplicate logic..
final Intent intent = kgm.createConfirmDeviceCredentialIntent(null /* title */,
null /* description */);
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index b65535af52b1..9e0f2fcaa29f 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -624,7 +624,8 @@ public abstract class BiometricServiceBase extends SystemService
handleError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
0 /*vendorCode */);
- StatsLog.write(StatsLog.BIOMETRIC_HAL_DEATH_REPORTED, statsModality());
+ StatsLog.write(StatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, statsModality(),
+ BiometricsProtoEnums.ISSUE_HAL_DEATH);
}
protected ClientMonitor getCurrentClient() {
diff --git a/services/core/java/com/android/server/biometrics/LoggableMonitor.java b/services/core/java/com/android/server/biometrics/LoggableMonitor.java
index 91c924de27a2..3b75b95fb0b9 100644
--- a/services/core/java/com/android/server/biometrics/LoggableMonitor.java
+++ b/services/core/java/com/android/server/biometrics/LoggableMonitor.java
@@ -28,7 +28,7 @@ import android.util.StatsLog;
public abstract class LoggableMonitor {
public static final String TAG = "BiometricStats";
- public static final boolean DEBUG = true;
+ public static final boolean DEBUG = false;
private long mFirstAcquireTimeMs;
@@ -137,6 +137,8 @@ public abstract class LoggableMonitor {
+ ", RequireConfirmation: " + requireConfirmation
+ ", State: " + authState
+ ", Latency: " + latency);
+ } else {
+ Slog.v(TAG, "Authentication latency: " + latency);
}
StatsLog.write(StatsLog.BIOMETRIC_AUTHENTICATED,
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 8995068ef504..eab38209c194 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -588,6 +588,11 @@ public class FaceService extends BiometricServiceBase {
throws RemoteException {
// TODO
}
+
+ @Override
+ public void onLockoutChanged(long duration) {
+
+ }
};
/**
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 9e0a1c0c2ef2..d8544e324618 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -49,6 +49,7 @@ import android.os.SELinux;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;
+import android.util.StatsLog;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
@@ -554,6 +555,8 @@ public class FingerprintService extends BiometricServiceBase {
+ " " + f.getDeviceId());
FingerprintUtils.getInstance().removeBiometricForUser(getContext(),
getTargetUserId(), f.getBiometricId());
+ StatsLog.write(StatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
+ BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_FRAMEWORK);
}
mEnrolledList.clear();
}
@@ -1003,6 +1006,8 @@ public class FingerprintService extends BiometricServiceBase {
mHalDeviceId, mToken, new ServiceListenerImpl(null), uf.f.getBiometricId(),
uf.f.getGroupId(), uf.userId, restricted, getContext().getOpPackageName());
removeInternal(client);
+ StatsLog.write(StatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, statsModality(),
+ BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL);
} else {
clearEnumerateState();
}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index a14fd17209e8..19bdc0969e6d 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -96,6 +96,7 @@ import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.MessageUtils;
@@ -180,6 +181,7 @@ public class Tethering extends BaseNetworkObserver {
// into a single coherent structure.
private final HashSet<IpServer> mForwardedDownstreams;
private final VersionedBroadcastListener mCarrierConfigChange;
+ private final VersionedBroadcastListener mDefaultSubscriptionChange;
private final TetheringDependencies mDeps;
private final EntitlementManager mEntitlementMgr;
@@ -232,6 +234,15 @@ public class Tethering extends BaseNetworkObserver {
mEntitlementMgr.reevaluateSimCardProvisioning();
});
+ filter = new IntentFilter();
+ filter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
+ mDefaultSubscriptionChange = new VersionedBroadcastListener(
+ "DefaultSubscriptionChangeListener", mContext, smHandler, filter,
+ (Intent ignored) -> {
+ mLog.log("OBSERVED default data subscription change");
+ updateConfiguration();
+ mEntitlementMgr.reevaluateSimCardProvisioning();
+ });
mStateReceiver = new StateReceiver();
// Load tethering configuration.
@@ -242,6 +253,7 @@ public class Tethering extends BaseNetworkObserver {
private void startStateMachineUpdaters() {
mCarrierConfigChange.startListening();
+ mDefaultSubscriptionChange.startListening();
final Handler handler = mTetherMasterSM.getHandler();
IntentFilter filter = new IntentFilter();
@@ -270,7 +282,8 @@ public class Tethering extends BaseNetworkObserver {
// NOTE: This is always invoked on the mLooper thread.
private void updateConfiguration() {
- mConfig = new TetheringConfiguration(mContext, mLog);
+ final int subId = mDeps.getDefaultDataSubscriptionId();
+ mConfig = new TetheringConfiguration(mContext, mLog, subId);
mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired);
mEntitlementMgr.updateConfiguration(mConfig);
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
index 1e6bb04858a1..8a46ff18979f 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -26,8 +26,8 @@ import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER;
import static com.android.internal.R.array.config_mobile_hotspot_provision_app;
import static com.android.internal.R.array.config_tether_bluetooth_regexs;
import static com.android.internal.R.array.config_tether_dhcp_range;
-import static com.android.internal.R.array.config_tether_usb_regexs;
import static com.android.internal.R.array.config_tether_upstream_types;
+import static com.android.internal.R.array.config_tether_usb_regexs;
import static com.android.internal.R.array.config_tether_wifi_regexs;
import static com.android.internal.R.bool.config_tether_upstream_automatic;
import static com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui;
@@ -38,6 +38,7 @@ import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.util.SharedLog;
import android.provider.Settings;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -100,29 +101,34 @@ public class TetheringConfiguration {
public final String[] provisioningApp;
public final String provisioningAppNoUi;
- public TetheringConfiguration(Context ctx, SharedLog log) {
+ public final int subId;
+
+ public TetheringConfiguration(Context ctx, SharedLog log, int id) {
final SharedLog configLog = log.forSubComponent("config");
- tetherableUsbRegexs = getResourceStringArray(ctx, config_tether_usb_regexs);
+ subId = id;
+ Resources res = getResources(ctx, subId);
+
+ tetherableUsbRegexs = getResourceStringArray(res, config_tether_usb_regexs);
// TODO: Evaluate deleting this altogether now that Wi-Fi always passes
// us an interface name. Careful consideration needs to be given to
// implications for Settings and for provisioning checks.
- tetherableWifiRegexs = getResourceStringArray(ctx, config_tether_wifi_regexs);
- tetherableBluetoothRegexs = getResourceStringArray(ctx, config_tether_bluetooth_regexs);
+ tetherableWifiRegexs = getResourceStringArray(res, config_tether_wifi_regexs);
+ tetherableBluetoothRegexs = getResourceStringArray(res, config_tether_bluetooth_regexs);
dunCheck = checkDunRequired(ctx);
configLog.log("DUN check returned: " + dunCheckString(dunCheck));
- chooseUpstreamAutomatically = getResourceBoolean(ctx, config_tether_upstream_automatic);
- preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, dunCheck);
+ chooseUpstreamAutomatically = getResourceBoolean(res, config_tether_upstream_automatic);
+ preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, dunCheck);
isDunRequired = preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN);
- legacyDhcpRanges = getLegacyDhcpRanges(ctx);
+ legacyDhcpRanges = getLegacyDhcpRanges(res);
defaultIPv4DNS = copy(DEFAULT_IPV4_DNS);
enableLegacyDhcpServer = getEnableLegacyDhcpServer(ctx);
- provisioningApp = getResourceStringArray(ctx, config_mobile_hotspot_provision_app);
- provisioningAppNoUi = getProvisioningAppNoUi(ctx);
+ provisioningApp = getResourceStringArray(res, config_mobile_hotspot_provision_app);
+ provisioningAppNoUi = getProvisioningAppNoUi(res);
configLog.log(toString());
}
@@ -144,6 +150,9 @@ public class TetheringConfiguration {
}
public void dump(PrintWriter pw) {
+ pw.print("subId: ");
+ pw.println(subId);
+
dumpStringArray(pw, "tetherableUsbRegexs", tetherableUsbRegexs);
dumpStringArray(pw, "tetherableWifiRegexs", tetherableWifiRegexs);
dumpStringArray(pw, "tetherableBluetoothRegexs", tetherableBluetoothRegexs);
@@ -169,6 +178,7 @@ public class TetheringConfiguration {
public String toString() {
final StringJoiner sj = new StringJoiner(" ");
+ sj.add(String.format("subId:%d", subId));
sj.add(String.format("tetherableUsbRegexs:%s", makeString(tetherableUsbRegexs)));
sj.add(String.format("tetherableWifiRegexs:%s", makeString(tetherableWifiRegexs)));
sj.add(String.format("tetherableBluetoothRegexs:%s",
@@ -235,8 +245,8 @@ public class TetheringConfiguration {
}
}
- private static Collection<Integer> getUpstreamIfaceTypes(Context ctx, int dunCheck) {
- final int ifaceTypes[] = ctx.getResources().getIntArray(config_tether_upstream_types);
+ private static Collection<Integer> getUpstreamIfaceTypes(Resources res, int dunCheck) {
+ final int[] ifaceTypes = res.getIntArray(config_tether_upstream_types);
final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length);
for (int i : ifaceTypes) {
switch (i) {
@@ -286,33 +296,33 @@ public class TetheringConfiguration {
return false;
}
- private static String[] getLegacyDhcpRanges(Context ctx) {
- final String[] fromResource = getResourceStringArray(ctx, config_tether_dhcp_range);
+ private static String[] getLegacyDhcpRanges(Resources res) {
+ final String[] fromResource = getResourceStringArray(res, config_tether_dhcp_range);
if ((fromResource.length > 0) && (fromResource.length % 2 == 0)) {
return fromResource;
}
return copy(LEGACY_DHCP_DEFAULT_RANGE);
}
- private static String getProvisioningAppNoUi(Context ctx) {
+ private static String getProvisioningAppNoUi(Resources res) {
try {
- return ctx.getResources().getString(config_mobile_hotspot_provision_app_no_ui);
+ return res.getString(config_mobile_hotspot_provision_app_no_ui);
} catch (Resources.NotFoundException e) {
return "";
}
}
- private static boolean getResourceBoolean(Context ctx, int resId) {
+ private static boolean getResourceBoolean(Resources res, int resId) {
try {
- return ctx.getResources().getBoolean(resId);
+ return res.getBoolean(resId);
} catch (Resources.NotFoundException e404) {
return false;
}
}
- private static String[] getResourceStringArray(Context ctx, int resId) {
+ private static String[] getResourceStringArray(Resources res, int resId) {
try {
- final String[] strArray = ctx.getResources().getStringArray(resId);
+ final String[] strArray = res.getStringArray(resId);
return (strArray != null) ? strArray : EMPTY_STRING_ARRAY;
} catch (Resources.NotFoundException e404) {
return EMPTY_STRING_ARRAY;
@@ -325,6 +335,19 @@ public class TetheringConfiguration {
return intVal != 0;
}
+ private Resources getResources(Context ctx, int subId) {
+ if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ return getResourcesForSubIdWrapper(ctx, subId);
+ } else {
+ return ctx.getResources();
+ }
+ }
+
+ @VisibleForTesting
+ protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) {
+ return SubscriptionManager.getResourcesForSubId(ctx, subId);
+ }
+
private static String[] copy(String[] strarray) {
return Arrays.copyOf(strarray, strarray.length);
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
index 6d6f81eb98e6..3fddac111ec5 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -21,6 +21,7 @@ import android.net.NetworkRequest;
import android.net.ip.IpServer;
import android.net.util.SharedLog;
import android.os.Handler;
+import android.telephony.SubscriptionManager;
import com.android.internal.util.StateMachine;
import com.android.server.connectivity.MockableSystemProperties;
@@ -85,4 +86,11 @@ public class TetheringDependencies {
SharedLog log, MockableSystemProperties systemProperties) {
return new EntitlementManager(ctx, target, log, systemProperties);
}
+
+ /**
+ * Get default data subscription id to build TetheringConfiguration.
+ */
+ public int getDefaultDataSubscriptionId() {
+ return SubscriptionManager.getDefaultDataSubscriptionId();
+ }
}
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index 9cb6eeec2126..45f169ca0b6f 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -387,8 +387,10 @@ public final class ColorDisplayService extends SystemService {
Slog.d(TAG, "Setting saturation level: " + saturationLevel);
if (saturationLevel == 100) {
+ setActivated(false);
Matrix.setIdentityM(mMatrixGlobalSaturation, 0);
} else {
+ setActivated(true);
float saturation = saturationLevel * 0.1f;
float desaturation = 1.0f - saturation;
float[] luminance = {0.231f * desaturation, 0.715f * desaturation,
@@ -556,14 +558,16 @@ public final class ColorDisplayService extends SystemService {
if (setting != null) {
switch (setting) {
case Secure.NIGHT_DISPLAY_ACTIVATED:
- final boolean activated = isNightDisplayActivatedSetting();
+ final boolean activated = mNightDisplayTintController
+ .isActivatedSetting();
if (mNightDisplayTintController.isActivatedStateNotSet()
|| mNightDisplayTintController.isActivated() != activated) {
- mNightDisplayTintController.onActivated(activated);
+ mNightDisplayTintController.setActivated(activated);
}
break;
case Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE:
- final int temperature = getNightDisplayColorTemperatureSetting();
+ final int temperature = mNightDisplayTintController
+ .getColorTemperatureSetting();
if (mNightDisplayTintController.getColorTemperature()
!= temperature) {
mNightDisplayTintController
@@ -639,14 +643,16 @@ public final class ColorDisplayService extends SystemService {
// Prepare the night display color transformation matrix.
mNightDisplayTintController
.setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
- mNightDisplayTintController.setMatrix(getNightDisplayColorTemperatureSetting());
+ mNightDisplayTintController
+ .setMatrix(mNightDisplayTintController.getColorTemperatureSetting());
// Initialize the current auto mode.
onNightDisplayAutoModeChanged(getNightDisplayAutoModeInternal());
// Force the initialization of the current saved activation state.
if (mNightDisplayTintController.isActivatedStateNotSet()) {
- mNightDisplayTintController.onActivated(isNightDisplayActivatedSetting());
+ mNightDisplayTintController
+ .setActivated(mNightDisplayTintController.isActivatedSetting());
}
}
@@ -674,6 +680,10 @@ public final class ColorDisplayService extends SystemService {
if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
mDisplayWhiteBalanceTintController.endAnimator();
}
+
+ if (mGlobalSaturationTintController.isAvailable(getContext())) {
+ mGlobalSaturationTintController.setActivated(null);
+ }
}
private void onNightDisplayAutoModeChanged(int autoMode) {
@@ -722,7 +732,8 @@ public final class ColorDisplayService extends SystemService {
if (mNightDisplayTintController.isAvailable(getContext())) {
mNightDisplayTintController
.setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
- mNightDisplayTintController.setMatrix(getNightDisplayColorTemperatureSetting());
+ mNightDisplayTintController
+ .setMatrix(mNightDisplayTintController.getColorTemperatureSetting());
}
updateDisplayWhiteBalanceStatus();
@@ -1040,8 +1051,7 @@ public final class ColorDisplayService extends SystemService {
*
* See {@link com.android.server.display.DisplayTransformManager}
*/
- private @ColorMode
- int getCurrentColorModeFromSystemProperties() {
+ private @ColorMode int getCurrentColorModeFromSystemProperties() {
final int displayColorSetting = SystemProperties.getInt("persist.sys.sf.native_mode", 0);
if (displayColorSetting == 0) {
return "1.0".equals(SystemProperties.get("persist.sys.sf.color_saturation"))
@@ -1098,33 +1108,6 @@ public final class ColorDisplayService extends SystemService {
pw.println("Color mode: " + getColorModeInternal());
}
- private boolean isNightDisplayActivatedSetting() {
- return Secure.getIntForUser(getContext().getContentResolver(),
- Secure.NIGHT_DISPLAY_ACTIVATED, 0, mCurrentUser) == 1;
- }
-
- private int getNightDisplayColorTemperatureSetting() {
- return clampNightDisplayColorTemperature(Secure.getIntForUser(
- getContext().getContentResolver(), Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, NOT_SET,
- mCurrentUser));
- }
-
- private int clampNightDisplayColorTemperature(int colorTemperature) {
- if (colorTemperature == NOT_SET) {
- colorTemperature = getContext().getResources().getInteger(
- R.integer.config_nightDisplayColorTemperatureDefault);
- }
- final int minimumTemperature = ColorDisplayManager.getMinimumColorTemperature(getContext());
- final int maximumTemperature = ColorDisplayManager.getMaximumColorTemperature(getContext());
- if (colorTemperature < minimumTemperature) {
- colorTemperature = minimumTemperature;
- } else if (colorTemperature > maximumTemperature) {
- colorTemperature = maximumTemperature;
- }
-
- return colorTemperature;
- }
-
private abstract class NightDisplayAutoMode {
public abstract void onActivated(boolean activated);
@@ -1171,7 +1154,7 @@ public final class ColorDisplayService extends SystemService {
// Maintain the existing activated state if within the current period.
if (mLastActivatedTime.isBefore(now) && mLastActivatedTime.isAfter(start)
&& (mLastActivatedTime.isAfter(end) || now.isBefore(end))) {
- activate = isNightDisplayActivatedSetting();
+ activate = mNightDisplayTintController.isActivatedSetting();
}
}
@@ -1267,7 +1250,7 @@ public final class ColorDisplayService extends SystemService {
// Maintain the existing activated state if within the current period.
if (mLastActivatedTime.isBefore(now) && (mLastActivatedTime.isBefore(sunrise)
^ mLastActivatedTime.isBefore(sunset))) {
- activate = isNightDisplayActivatedSetting();
+ activate = mNightDisplayTintController.isActivatedSetting();
}
}
@@ -1466,9 +1449,11 @@ public final class ColorDisplayService extends SystemService {
if (isActivatedStateNotSet() || activationStateChanged) {
super.setActivated(activated);
- Secure.putIntForUser(getContext().getContentResolver(),
- Secure.NIGHT_DISPLAY_ACTIVATED,
- activated ? 1 : 0, mCurrentUser);
+ if (isActivatedSetting() != activated) {
+ Secure.putIntForUser(getContext().getContentResolver(),
+ Secure.NIGHT_DISPLAY_ACTIVATED,
+ activated ? 1 : 0, mCurrentUser);
+ }
onActivated(activated);
}
}
@@ -1486,7 +1471,7 @@ public final class ColorDisplayService extends SystemService {
return mIsAvailable;
}
- void onActivated(boolean activated) {
+ private void onActivated(boolean activated) {
Slog.i(TAG, activated ? "Turning on night display" : "Turning off night display");
if (mNightDisplayAutoMode != null) {
mNightDisplayAutoMode.onActivated(activated);
@@ -1501,7 +1486,7 @@ public final class ColorDisplayService extends SystemService {
int getColorTemperature() {
return mColorTemp != null ? clampNightDisplayColorTemperature(mColorTemp)
- : getNightDisplayColorTemperatureSetting();
+ : getColorTemperatureSetting();
}
boolean setColorTemperature(int temperature) {
@@ -1516,6 +1501,36 @@ public final class ColorDisplayService extends SystemService {
setMatrix(temperature);
mHandler.sendEmptyMessage(MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE);
}
+
+ boolean isActivatedSetting() {
+ return Secure.getIntForUser(getContext().getContentResolver(),
+ Secure.NIGHT_DISPLAY_ACTIVATED, 0, mCurrentUser) == 1;
+ }
+
+ int getColorTemperatureSetting() {
+ return clampNightDisplayColorTemperature(Secure.getIntForUser(
+ getContext().getContentResolver(), Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE,
+ NOT_SET,
+ mCurrentUser));
+ }
+
+ private int clampNightDisplayColorTemperature(int colorTemperature) {
+ if (colorTemperature == NOT_SET) {
+ colorTemperature = getContext().getResources().getInteger(
+ R.integer.config_nightDisplayColorTemperatureDefault);
+ }
+ final int minimumTemperature = ColorDisplayManager
+ .getMinimumColorTemperature(getContext());
+ final int maximumTemperature = ColorDisplayManager
+ .getMaximumColorTemperature(getContext());
+ if (colorTemperature < minimumTemperature) {
+ colorTemperature = minimumTemperature;
+ } else if (colorTemperature > maximumTemperature) {
+ colorTemperature = maximumTemperature;
+ }
+
+ return colorTemperature;
+ }
}
/**
@@ -1671,6 +1686,20 @@ public final class ColorDisplayService extends SystemService {
}
@Override
+ public boolean isSaturationActivated() {
+ getContext().enforceCallingPermission(
+ Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
+ "Permission required to get display saturation level");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return !mGlobalSaturationTintController.isActivatedStateNotSet()
+ && mGlobalSaturationTintController.isActivated();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
public boolean setAppSaturationLevel(String packageName, int level) {
getContext().enforceCallingPermission(
Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 6ee5665b9e42..e9ae516cc8d0 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -19,6 +19,7 @@ package com.android.server.display;
import android.graphics.Rect;
import android.hardware.display.DisplayViewport;
import android.os.IBinder;
+import android.view.DisplayAddress;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -225,8 +226,12 @@ abstract class DisplayDevice {
viewport.deviceHeight = isRotated ? info.width : info.height;
viewport.uniqueId = info.uniqueId;
- // TODO(b/112898898) Use an actual port here.
- viewport.physicalPort = null;
+
+ if (info.address instanceof DisplayAddress.Physical) {
+ viewport.physicalPort = ((DisplayAddress.Physical) info.address).getPort();
+ } else {
+ viewport.physicalPort = null;
+ }
}
/**
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index ab64f61a3b22..729ea1772066 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -19,6 +19,7 @@ package com.android.server.display;
import android.hardware.display.DisplayViewport;
import android.util.DisplayMetrics;
import android.view.Display;
+import android.view.DisplayAddress;
import android.view.DisplayCutout;
import android.view.Surface;
@@ -274,7 +275,7 @@ final class DisplayDeviceInfo {
* Display address, or null if none.
* Interpretation varies by display type.
*/
- public String address;
+ public DisplayAddress address;
/**
* Display state.
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 80ea1dae3115..b99ba7ed0bf0 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1336,7 +1336,7 @@ public final class DisplayManagerService extends SystemService {
&& !TextUtils.isEmpty(info.uniqueId)) {
viewportType = VIEWPORT_VIRTUAL;
} else {
- Slog.wtf(TAG, "Unable to populate viewport for display device: " + info);
+ Slog.i(TAG, "Display " + info + " does not support input device matching.");
return;
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 28f21f633ac4..489194726c5a 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -31,6 +31,7 @@ import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
+import android.view.DisplayAddress;
import android.view.DisplayCutout;
import android.view.DisplayEventReceiver;
import android.view.Surface;
@@ -382,6 +383,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mInfo.presentationDeadlineNanos = phys.presentationDeadlineNanos;
mInfo.state = mState;
mInfo.uniqueId = getUniqueId();
+ mInfo.address = DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId);
// Assume that all built-in displays that have secure output (eg. HDCP) also
// support compositing from gralloc protected buffers.
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index e8d6ad455fbf..9e4c1cb57dca 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -16,9 +16,6 @@
package com.android.server.display;
-import com.android.internal.util.DumpUtils;
-import com.android.internal.util.IndentingPrintWriter;
-
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -35,9 +32,13 @@ import android.os.Message;
import android.os.UserHandle;
import android.util.Slog;
import android.view.Display;
+import android.view.DisplayAddress;
import android.view.Surface;
import android.view.SurfaceControl;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -581,7 +582,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
private final int mHeight;
private final float mRefreshRate;
private final int mFlags;
- private final String mAddress;
+ private final DisplayAddress mAddress;
private final Display.Mode mMode;
private Surface mSurface;
@@ -596,7 +597,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
mHeight = height;
mRefreshRate = refreshRate;
mFlags = flags;
- mAddress = address;
+ mAddress = DisplayAddress.fromMacAddress(address);
mSurface = surface;
mMode = createMode(width, height, refreshRate);
}
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
index 7ae00af626c8..b9aa34e89216 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
@@ -18,6 +18,7 @@ package com.android.server.display.whitebalance;
import android.annotation.NonNull;
import android.util.Slog;
+import android.util.Spline;
import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
@@ -75,6 +76,9 @@ public class DisplayWhiteBalanceController implements
// Override the ambient color temperature for debugging purposes.
private float mAmbientColorTemperatureOverride;
+ // A piecewise linear relationship between ambient and display color temperatures
+ private Spline.LinearSpline mAmbientToDisplayTemperatureSpline;
+
/**
* @param brightnessSensor
* The sensor used to detect changes in the ambient brightness.
@@ -109,7 +113,8 @@ public class DisplayWhiteBalanceController implements
@NonNull AmbientSensor.AmbientColorTemperatureSensor colorTemperatureSensor,
@NonNull AmbientFilter colorTemperatureFilter,
@NonNull DisplayWhiteBalanceThrottler throttler,
- float lowLightAmbientBrightnessThreshold, float lowLightAmbientColorTemperature) {
+ float lowLightAmbientBrightnessThreshold, float lowLightAmbientColorTemperature,
+ float[] ambientTemperatures, float[] displayTemperatures) {
validateArguments(brightnessSensor, brightnessFilter, colorTemperatureSensor,
colorTemperatureFilter, throttler);
mLoggingEnabled = false;
@@ -127,6 +132,14 @@ public class DisplayWhiteBalanceController implements
mLastAmbientColorTemperature = -1.0f;
mAmbientColorTemperatureHistory = new History(HISTORY_SIZE);
mAmbientColorTemperatureOverride = -1.0f;
+
+ try {
+ mAmbientToDisplayTemperatureSpline = new Spline.LinearSpline(ambientTemperatures,
+ displayTemperatures);
+ } catch (Exception e) {
+ mAmbientToDisplayTemperatureSpline = null;
+ }
+
mColorDisplayServiceInternal = LocalServices.getService(ColorDisplayServiceInternal.class);
}
@@ -227,6 +240,9 @@ public class DisplayWhiteBalanceController implements
writer.println(" mLastAmbientColorTemperature=" + mLastAmbientColorTemperature);
writer.println(" mAmbientColorTemperatureHistory=" + mAmbientColorTemperatureHistory);
writer.println(" mAmbientColorTemperatureOverride=" + mAmbientColorTemperatureOverride);
+ writer.println(" mAmbientToDisplayTemperatureSpline="
+ + (mAmbientToDisplayTemperatureSpline == null ? "unused" :
+ mAmbientToDisplayTemperatureSpline));
}
@Override // AmbientSensor.AmbientBrightnessSensor.Callbacks
@@ -250,6 +266,11 @@ public class DisplayWhiteBalanceController implements
final long time = System.currentTimeMillis();
float ambientColorTemperature = mColorTemperatureFilter.getEstimate(time);
+ if (mAmbientToDisplayTemperatureSpline != null) {
+ ambientColorTemperature =
+ mAmbientToDisplayTemperatureSpline.interpolate(ambientColorTemperature);
+ }
+
final float ambientBrightness = mBrightnessFilter.getEstimate(time);
if (ambientBrightness < mLowLightAmbientBrightnessThreshold) {
if (mLoggingEnabled) {
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
index fd78ddbda9c8..56f4ca339eb3 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
@@ -67,9 +67,14 @@ public class DisplayWhiteBalanceFactory {
final float lowLightAmbientColorTemperature = getFloat(resources,
com.android.internal.R.dimen
.config_displayWhiteBalanceLowLightAmbientColorTemperature);
+ final float[] ambientTemperatures = getFloatArray(resources,
+ com.android.internal.R.array.config_displayWhiteBalanceAmbientTemperatureValues);
+ final float[] displayTemperatures = getFloatArray(resources,
+ com.android.internal.R.array.config_displayWhiteBalanceDisplayTemperatureValues);
final DisplayWhiteBalanceController controller = new DisplayWhiteBalanceController(
brightnessSensor, brightnessFilter, colorTemperatureSensor, colorTemperatureFilter,
- throttler, lowLightAmbientBrightnessThreshold, lowLightAmbientColorTemperature);
+ throttler, lowLightAmbientBrightnessThreshold, lowLightAmbientColorTemperature,
+ ambientTemperatures, displayTemperatures);
brightnessSensor.setCallbacks(controller);
colorTemperatureSensor.setCallbacks(controller);
return controller;
diff --git a/services/core/java/com/android/server/gpu/GpuService.java b/services/core/java/com/android/server/gpu/GpuService.java
index a68ceed750ad..6899c3ffcbb1 100644
--- a/services/core/java/com/android/server/gpu/GpuService.java
+++ b/services/core/java/com/android/server/gpu/GpuService.java
@@ -22,24 +22,33 @@ import static android.content.Intent.ACTION_PACKAGE_REMOVED;
import android.annotation.NonNull;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.gamedriver.GameDriverProto.Blacklist;
+import android.gamedriver.GameDriverProto.Blacklists;
import android.net.Uri;
import android.os.Build;
+import android.os.Handler;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
+import android.util.Base64;
import android.util.Slog;
+import com.android.framework.protobuf.InvalidProtocolBufferException;
+import com.android.internal.annotations.GuardedBy;
import com.android.server.SystemService;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
+import java.util.List;
/**
* Service to manage GPU related features.
@@ -52,17 +61,25 @@ public class GpuService extends SystemService {
public static final boolean DEBUG = false;
private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
- private static final String WHITELIST_FILENAME = "whitelist.txt";
+ private static final String GAME_DRIVER_WHITELIST_FILENAME = "whitelist.txt";
+ private static final int BASE64_FLAGS = Base64.NO_PADDING | Base64.NO_WRAP;
private final Context mContext;
private final String mDriverPackageName;
private final PackageManager mPackageManager;
+ private final Object mLock = new Object();
+ private ContentResolver mContentResolver;
+ private long mGameDriverVersionCode;
+ private SettingsObserver mSettingsObserver;
+ @GuardedBy("mLock")
+ private Blacklists mBlacklists;
public GpuService(Context context) {
super(context);
mContext = context;
mDriverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER);
+ mGameDriverVersionCode = -1;
mPackageManager = context.getPackageManager();
if (mDriverPackageName != null && !mDriverPackageName.isEmpty()) {
final IntentFilter packageFilter = new IntentFilter();
@@ -82,10 +99,37 @@ public class GpuService extends SystemService {
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_BOOT_COMPLETED) {
+ mContentResolver = mContext.getContentResolver();
+ mSettingsObserver = new SettingsObserver();
if (mDriverPackageName == null || mDriverPackageName.isEmpty()) {
return;
}
fetchGameDriverPackageProperties();
+ processBlacklists();
+ setBlacklist();
+ }
+ }
+
+ private final class SettingsObserver extends ContentObserver {
+ private final Uri mGameDriverBlackUri =
+ Settings.Global.getUriFor(Settings.Global.GAME_DRIVER_BLACKLISTS);
+
+ SettingsObserver() {
+ super(new Handler());
+ mContentResolver.registerContentObserver(mGameDriverBlackUri, false, this,
+ UserHandle.USER_ALL);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (uri == null) {
+ return;
+ }
+
+ if (mGameDriverBlackUri.equals(uri)) {
+ processBlacklists();
+ setBlacklist();
+ }
}
}
@@ -109,6 +153,7 @@ public class GpuService extends SystemService {
case ACTION_PACKAGE_CHANGED:
case ACTION_PACKAGE_REMOVED:
fetchGameDriverPackageProperties();
+ setBlacklist();
break;
default:
// do nothing
@@ -138,16 +183,22 @@ public class GpuService extends SystemService {
return;
}
+ // Reset the whitelist.
+ Settings.Global.putString(mContentResolver,
+ Settings.Global.GAME_DRIVER_WHITELIST, "");
+ mGameDriverVersionCode = driverInfo.longVersionCode;
+
try {
final Context driverContext = mContext.createPackageContext(mDriverPackageName,
Context.CONTEXT_RESTRICTED);
final BufferedReader reader = new BufferedReader(
- new InputStreamReader(driverContext.getAssets().open(WHITELIST_FILENAME)));
+ new InputStreamReader(driverContext.getAssets()
+ .open(GAME_DRIVER_WHITELIST_FILENAME)));
final ArrayList<String> whitelistedPackageNames = new ArrayList<>();
for (String packageName; (packageName = reader.readLine()) != null; ) {
whitelistedPackageNames.add(packageName);
}
- Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.putString(mContentResolver,
Settings.Global.GAME_DRIVER_WHITELIST,
String.join(",", whitelistedPackageNames));
} catch (PackageManager.NameNotFoundException e) {
@@ -160,4 +211,48 @@ public class GpuService extends SystemService {
}
}
}
+
+ private void processBlacklists() {
+ // TODO(b/121350991) Switch to DeviceConfig with property listener.
+ String base64String =
+ Settings.Global.getString(mContentResolver, Settings.Global.GAME_DRIVER_BLACKLISTS);
+ if (base64String == null || base64String.isEmpty()) {
+ return;
+ }
+
+ synchronized (mLock) {
+ // Reset all blacklists
+ mBlacklists = null;
+ try {
+ mBlacklists = Blacklists.parseFrom(Base64.decode(base64String, BASE64_FLAGS));
+ } catch (IllegalArgumentException e) {
+ if (DEBUG) {
+ Slog.w(TAG, "Can't parse blacklist, skip and continue...");
+ }
+ } catch (InvalidProtocolBufferException e) {
+ if (DEBUG) {
+ Slog.w(TAG, "Can't parse blacklist, skip and continue...");
+ }
+ }
+ }
+ }
+
+ private void setBlacklist() {
+ Settings.Global.putString(mContentResolver,
+ Settings.Global.GAME_DRIVER_BLACKLIST, "");
+ synchronized (mLock) {
+ if (mBlacklists == null) {
+ return;
+ }
+ List<Blacklist> blacklists = mBlacklists.getBlacklistsList();
+ for (Blacklist blacklist : blacklists) {
+ if (blacklist.getVersionCode() == mGameDriverVersionCode) {
+ Settings.Global.putString(mContentResolver,
+ Settings.Global.GAME_DRIVER_BLACKLIST,
+ String.join(",", blacklist.getPackageNamesList()));
+ return;
+ }
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 20933db803b9..560f7a03b20f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -342,7 +342,7 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
super.disableDevice(initiatedByCec, callback);
assertRunOnServiceThread();
- if (!initiatedByCec && mIsActiveSource) {
+ if (!initiatedByCec && mIsActiveSource && mService.isControlEnabled()) {
mService.sendCecCommand(HdmiCecMessageBuilder.buildInactiveSource(
mAddress, mService.getPhysicalAddress()));
}
diff --git a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
index cf84e22e7dd1..1b237949a543 100644
--- a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
+++ b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
@@ -187,7 +187,7 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR
@Override
public boolean isDefaultServiceEnabled(int userId) {
synchronized (mLock) {
- return mDefaultServicesDisabled.get(userId);
+ return !mDefaultServicesDisabled.get(userId);
}
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 5e7ea05f799c..28393a209111 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1805,9 +1805,10 @@ public class InputManagerService extends IInputManager.Stub
}
// Native callback.
- private int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
+ private int interceptMotionBeforeQueueingNonInteractive(int displayId,
+ long whenNanos, int policyFlags) {
return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive(
- whenNanos, policyFlags);
+ displayId, whenNanos, policyFlags);
}
// Native callback.
@@ -2021,7 +2022,13 @@ public class InputManagerService extends IInputManager.Stub
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
- public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);
+ /**
+ * Provides an opportunity for the window manager policy to intercept early motion event
+ * processing when the device is in a non-interactive state since these events are normally
+ * dropped.
+ */
+ int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
+ int policyFlags);
public long interceptKeyBeforeDispatching(IBinder token,
KeyEvent event, int policyFlags);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 144f2b6b143f..96ba0841855c 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -667,13 +667,19 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
final int mSequenceNumber;
final long mTimestamp;
final long mWallTime;
+ @UserIdInt
+ final int mImeUserId;
@NonNull
final IBinder mImeToken;
+ final int mImeDisplayId;
@NonNull
final String mImeId;
@StartInputReason
final int mStartInputReason;
final boolean mRestarting;
+ @UserIdInt
+ final int mTargetUserId;
+ final int mTargetDisplayId;
@Nullable
final IBinder mTargetWindow;
@NonNull
@@ -682,17 +688,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
final int mTargetWindowSoftInputMode;
final int mClientBindSequenceNumber;
- StartInputInfo(@NonNull IBinder imeToken, @NonNull String imeId,
- @StartInputReason int startInputReason, boolean restarting,
- @Nullable IBinder targetWindow, @NonNull EditorInfo editorInfo,
- @SoftInputModeFlags int targetWindowSoftInputMode, int clientBindSequenceNumber) {
+ StartInputInfo(@UserIdInt int imeUserId, @NonNull IBinder imeToken, int imeDisplayId,
+ @NonNull String imeId, @StartInputReason int startInputReason, boolean restarting,
+ @UserIdInt int targetUserId, int targetDisplayId, @Nullable IBinder targetWindow,
+ @NonNull EditorInfo editorInfo, @SoftInputModeFlags int targetWindowSoftInputMode,
+ int clientBindSequenceNumber) {
mSequenceNumber = sSequenceNumber.getAndIncrement();
mTimestamp = SystemClock.uptimeMillis();
mWallTime = System.currentTimeMillis();
+ mImeUserId = imeUserId;
mImeToken = imeToken;
+ mImeDisplayId = imeDisplayId;
mImeId = imeId;
mStartInputReason = startInputReason;
mRestarting = restarting;
+ mTargetUserId = targetUserId;
+ mTargetDisplayId = targetDisplayId;
mTargetWindow = targetWindow;
mEditorInfo = editorInfo;
mTargetWindowSoftInputMode = targetWindowSoftInputMode;
@@ -749,13 +760,19 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
int mSequenceNumber;
long mTimestamp;
long mWallTime;
+ @UserIdInt
+ int mImeUserId;
@NonNull
String mImeTokenString;
+ int mImeDisplayId;
@NonNull
String mImeId;
@StartInputReason
int mStartInputReason;
boolean mRestarting;
+ @UserIdInt
+ int mTargetUserId;
+ int mTargetDisplayId;
@NonNull
String mTargetWindowString;
@NonNull
@@ -772,12 +789,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mSequenceNumber = original.mSequenceNumber;
mTimestamp = original.mTimestamp;
mWallTime = original.mWallTime;
+ mImeUserId = original.mImeUserId;
// Intentionally convert to String so as not to keep a strong reference to a Binder
// object.
mImeTokenString = String.valueOf(original.mImeToken);
+ mImeDisplayId = original.mImeDisplayId;
mImeId = original.mImeId;
mStartInputReason = original.mStartInputReason;
mRestarting = original.mRestarting;
+ mTargetUserId = original.mTargetUserId;
+ mTargetDisplayId = original.mTargetDisplayId;
// Intentionally convert to String so as not to keep a strong reference to a Binder
// object.
mTargetWindowString = String.valueOf(original.mTargetWindow);
@@ -821,11 +842,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
+ " restarting=" + entry.mRestarting);
pw.print(prefix);
- pw.println(" imeToken=" + entry.mImeTokenString + " [" + entry.mImeId + "]");
+ pw.print(" imeToken=" + entry.mImeTokenString + " [" + entry.mImeId + "]");
+ pw.print(" imeUserId=" + entry.mImeUserId);
+ pw.println(" imeDisplayId=" + entry.mImeDisplayId);
pw.print(prefix);
pw.println(" targetWin=" + entry.mTargetWindowString
+ " [" + entry.mEditorInfo.packageName + "]"
+ + " targetUserId=" + entry.mTargetUserId
+ + " targetDisplayId=" + entry.mTargetDisplayId
+ " clientBindSeq=" + entry.mClientBindSequenceNumber);
pw.print(prefix);
@@ -1904,9 +1929,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
final Binder startInputToken = new Binder();
- final StartInputInfo info = new StartInputInfo(mCurToken, mCurId, startInputReason,
- !initial, mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode,
- mCurSeq);
+ final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(), mCurToken,
+ mCurTokenDisplayId, mCurId, startInputReason, !initial,
+ UserHandle.getUserId(mCurClient.uid), mCurClient.selfReportedDisplayId,
+ mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode, mCurSeq);
mImeTargetWindowMap.put(startInputToken, mCurFocusedWindow);
mStartInputHistory.addEntry(info);
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 19d10ecfb34d..cefe583fc5d1 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -509,7 +509,7 @@ public class JobSchedulerService extends com.android.server.SystemService
private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f;
private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f;
private static final boolean DEFAULT_USE_HEARTBEATS = false;
- private static final boolean DEFAULT_TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
+ private static final boolean DEFAULT_TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
private static final long DEFAULT_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS =
10 * 60 * 1000L; // 10 minutes
private static final long DEFAULT_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS =
diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java
index 97c3bac4ddbb..74628fb9b502 100644
--- a/services/core/java/com/android/server/job/controllers/StateController.java
+++ b/services/core/java/com/android/server/job/controllers/StateController.java
@@ -110,6 +110,7 @@ public abstract class StateController {
final boolean jobWouldBeReady = jobStatus.wouldBeReadyWithConstraint(constraint);
if (DEBUG) {
Slog.v(TAG, "wouldBeReadyWithConstraintLocked: " + jobStatus.toShortString()
+ + " constraint=" + constraint
+ " readyWithConstraint=" + jobWouldBeReady);
}
if (!jobWouldBeReady) {
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
index 26f3caf2e487..70deb38080b4 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -149,8 +149,8 @@ public final class TimeController extends StateController {
@Override
public void onConstantsUpdatedLocked() {
- checkExpiredDelaysAndResetAlarm();
checkExpiredDeadlinesAndResetAlarm();
+ checkExpiredDelaysAndResetAlarm();
}
@Override
@@ -159,20 +159,47 @@ public final class TimeController extends StateController {
return;
}
- if (job.hasTimingDelayConstraint()
- && job.getEarliestRunTime() <= mNextDelayExpiredElapsedMillis) {
- checkExpiredDelaysAndResetAlarm();
- }
+ final long nowElapsedMillis = sElapsedRealtimeClock.millis();
+
+ // Check deadline constraint first because if it's satisfied, we avoid a little bit of
+ // unnecessary processing of the timing delay.
if (job.hasDeadlineConstraint()
+ && !job.isConstraintSatisfied(JobStatus.CONSTRAINT_DEADLINE)
&& job.getLatestRunTimeElapsed() <= mNextJobExpiredElapsedMillis) {
- checkExpiredDeadlinesAndResetAlarm();
+ if (evaluateDeadlineConstraint(job, nowElapsedMillis)) {
+ checkExpiredDeadlinesAndResetAlarm();
+ checkExpiredDelaysAndResetAlarm();
+ } else {
+ final boolean isAlarmForJob =
+ job.getLatestRunTimeElapsed() == mNextJobExpiredElapsedMillis;
+ final boolean wouldBeReady = wouldBeReadyWithConstraintLocked(
+ job, JobStatus.CONSTRAINT_DEADLINE);
+ if ((isAlarmForJob && !wouldBeReady) || (!isAlarmForJob && wouldBeReady)) {
+ checkExpiredDeadlinesAndResetAlarm();
+ }
+ }
+ }
+ if (job.hasTimingDelayConstraint()
+ && !job.isConstraintSatisfied(JobStatus.CONSTRAINT_TIMING_DELAY)
+ && job.getEarliestRunTime() <= mNextDelayExpiredElapsedMillis) {
+ if (evaluateTimingDelayConstraint(job, nowElapsedMillis)) {
+ checkExpiredDelaysAndResetAlarm();
+ } else {
+ final boolean isAlarmForJob =
+ job.getEarliestRunTime() == mNextDelayExpiredElapsedMillis;
+ final boolean wouldBeReady = wouldBeReadyWithConstraintLocked(
+ job, JobStatus.CONSTRAINT_TIMING_DELAY);
+ if ((isAlarmForJob && !wouldBeReady) || (!isAlarmForJob && wouldBeReady)) {
+ checkExpiredDelaysAndResetAlarm();
+ }
+ }
}
}
@Override
public void reevaluateStateLocked(int uid) {
- checkExpiredDelaysAndResetAlarm();
checkExpiredDeadlinesAndResetAlarm();
+ checkExpiredDelaysAndResetAlarm();
}
/**
@@ -182,10 +209,10 @@ public final class TimeController extends StateController {
* back and forth.
*/
private boolean canStopTrackingJobLocked(JobStatus job) {
- return (!job.hasTimingDelayConstraint() ||
- (job.satisfiedConstraints&JobStatus.CONSTRAINT_TIMING_DELAY) != 0) &&
- (!job.hasDeadlineConstraint() ||
- (job.satisfiedConstraints&JobStatus.CONSTRAINT_DEADLINE) != 0);
+ return (!job.hasTimingDelayConstraint()
+ || job.isConstraintSatisfied(JobStatus.CONSTRAINT_TIMING_DELAY))
+ && (!job.hasDeadlineConstraint()
+ || job.isConstraintSatisfied(JobStatus.CONSTRAINT_DEADLINE));
}
private void ensureAlarmServiceLocked() {
@@ -241,6 +268,7 @@ public final class TimeController extends StateController {
}
}
+ /** @return true if the job's deadline constraint is satisfied */
private boolean evaluateDeadlineConstraint(JobStatus job, long nowElapsedMillis) {
final long jobDeadline = job.getLatestRunTimeElapsed();
@@ -279,7 +307,7 @@ public final class TimeController extends StateController {
if (job.isReady()) {
ready = true;
}
- } else if (!job.isConstraintSatisfied(JobStatus.CONSTRAINT_TIMING_DELAY)) {
+ } else {
if (mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS
&& !wouldBeReadyWithConstraintLocked(
job, JobStatus.CONSTRAINT_TIMING_DELAY)) {
@@ -319,6 +347,7 @@ public final class TimeController extends StateController {
}
}
+ /** @return true if the job's delay constraint is satisfied */
private boolean evaluateTimingDelayConstraint(JobStatus job, long nowElapsedMillis) {
final long jobDelayTime = job.getEarliestRunTime();
if (jobDelayTime <= nowElapsedMillis) {
@@ -347,6 +376,9 @@ public final class TimeController extends StateController {
*/
private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) {
alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
+ if (mNextDelayExpiredElapsedMillis == alarmTimeElapsedMillis) {
+ return;
+ }
mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis;
updateAlarmWithListenerLocked(DELAY_TAG, mNextDelayExpiredListener,
mNextDelayExpiredElapsedMillis, ws);
@@ -359,6 +391,9 @@ public final class TimeController extends StateController {
*/
private void setDeadlineExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) {
alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
+ if (mNextJobExpiredElapsedMillis == alarmTimeElapsedMillis) {
+ return;
+ }
mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis;
updateAlarmWithListenerLocked(DEADLINE_TAG, mDeadlineExpiredListener,
mNextJobExpiredElapsedMillis, ws);
diff --git a/services/core/java/com/android/server/location/GnssConfiguration.java b/services/core/java/com/android/server/location/GnssConfiguration.java
index 72259268aa81..91b5234e02e5 100644
--- a/services/core/java/com/android/server/location/GnssConfiguration.java
+++ b/services/core/java/com/android/server/location/GnssConfiguration.java
@@ -367,7 +367,7 @@ class GnssConfiguration {
return defaultValue;
}
try {
- return Integer.parseInt(valueString);
+ return Integer.decode(valueString);
} catch (NumberFormatException e) {
Log.e(TAG, "Unable to parse config parameter " + configParameter + " value: "
+ valueString + ". Using default value: " + defaultValue);
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index f368e7b8494e..e71b156c3e86 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -302,7 +302,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
MAX_RETRY_INTERVAL);
// true if we are enabled, protected by this
- private boolean mEnabled = true;
+ private boolean mEnabled;
private boolean mShutdown;
@@ -917,7 +917,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
synchronized (mLock) {
boolean enabled =
((mProviderRequest != null && mProviderRequest.reportLocation
- && mProviderRequest.forceLocation) || (
+ && mProviderRequest.locationSettingsIgnored) || (
mContext.getSystemService(LocationManager.class).isLocationEnabled()
&& !mDisableGps)) && !mShutdown;
if (enabled == mEnabled) {
@@ -976,7 +976,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest);
- if (mProviderRequest.reportLocation && !mDisableGps && isEnabled()) {
+ if (mProviderRequest.reportLocation && isEnabled()) {
// update client uids
updateClientUids(mWorkSource);
diff --git a/services/core/java/com/android/server/location/RemoteListenerHelper.java b/services/core/java/com/android/server/location/RemoteListenerHelper.java
index f03c99b0272e..aa8a25a36333 100644
--- a/services/core/java/com/android/server/location/RemoteListenerHelper.java
+++ b/services/core/java/com/android/server/location/RemoteListenerHelper.java
@@ -31,9 +31,11 @@ import java.util.HashMap;
import java.util.Map;
/**
- * A helper class, that handles operations in remote listeners, and tracks for remote process death.
+ * A helper class that handles operations in remote listeners.
+ *
+ * @param <TListener> the type of GNSS data listener.
*/
-abstract class RemoteListenerHelper<TListener extends IInterface> {
+public abstract class RemoteListenerHelper<TListener extends IInterface> {
protected static final int RESULT_SUCCESS = 0;
protected static final int RESULT_NOT_AVAILABLE = 1;
@@ -46,7 +48,7 @@ abstract class RemoteListenerHelper<TListener extends IInterface> {
protected final Handler mHandler;
private final String mTag;
- private final Map<IBinder, LinkedListener> mListenerMap = new HashMap<>();
+ private final Map<IBinder, IdentifiedListener> mListenerMap = new HashMap<>();
protected final Context mContext;
protected final AppOpsManager mAppOps;
@@ -71,24 +73,21 @@ abstract class RemoteListenerHelper<TListener extends IInterface> {
return mIsRegistered;
}
- public boolean addListener(@NonNull TListener listener, CallerIdentity callerIdentity) {
+ /**
+ * Adds GNSS data listener {@code listener} with caller identify {@code callerIdentify}.
+ */
+ public void addListener(@NonNull TListener listener, CallerIdentity callerIdentity) {
Preconditions.checkNotNull(listener, "Attempted to register a 'null' listener.");
IBinder binder = listener.asBinder();
- LinkedListener deathListener = new LinkedListener(listener, callerIdentity);
synchronized (mListenerMap) {
if (mListenerMap.containsKey(binder)) {
// listener already added
- return true;
- }
- try {
- binder.linkToDeath(deathListener, 0 /* flags */);
- } catch (RemoteException e) {
- // if the remote process registering the listener is already death, just swallow the
- // exception and return
- Log.v(mTag, "Remote listener already died.", e);
- return false;
+ return;
}
- mListenerMap.put(binder, deathListener);
+
+ IdentifiedListener identifiedListener = new IdentifiedListener(listener,
+ callerIdentity);
+ mListenerMap.put(binder, identifiedListener);
// update statuses we already know about, starting from the ones that will never change
int result;
@@ -107,26 +106,23 @@ abstract class RemoteListenerHelper<TListener extends IInterface> {
} else {
// at this point if the supported flag is not set, the notification will be sent
// asynchronously in the future
- return true;
+ return;
}
- post(deathListener, getHandlerOperation(result));
+ post(identifiedListener, getHandlerOperation(result));
}
- return true;
}
+ /**
+ * Remove GNSS data listener {@code listener}.
+ */
public void removeListener(@NonNull TListener listener) {
Preconditions.checkNotNull(listener, "Attempted to remove a 'null' listener.");
- IBinder binder = listener.asBinder();
- LinkedListener linkedListener;
synchronized (mListenerMap) {
- linkedListener = mListenerMap.remove(binder);
+ mListenerMap.remove(listener.asBinder());
if (mListenerMap.isEmpty()) {
tryUnregister();
}
}
- if (linkedListener != null) {
- binder.unlinkToDeath(linkedListener, 0 /* flags */);
- }
}
protected abstract boolean isAvailableInPlatform();
@@ -198,14 +194,15 @@ abstract class RemoteListenerHelper<TListener extends IInterface> {
}
private void foreachUnsafe(ListenerOperation<TListener> operation) {
- for (LinkedListener linkedListener : mListenerMap.values()) {
- post(linkedListener, operation);
+ for (IdentifiedListener identifiedListener : mListenerMap.values()) {
+ post(identifiedListener, operation);
}
}
- private void post(LinkedListener linkedListener, ListenerOperation<TListener> operation) {
+ private void post(IdentifiedListener identifiedListener,
+ ListenerOperation<TListener> operation) {
if (operation != null) {
- mHandler.post(new HandlerRunnable(linkedListener, operation));
+ mHandler.post(new HandlerRunnable(identifiedListener, operation));
}
}
@@ -259,35 +256,31 @@ abstract class RemoteListenerHelper<TListener extends IInterface> {
return RESULT_SUCCESS;
}
- private class LinkedListener implements IBinder.DeathRecipient {
+ private class IdentifiedListener {
private final TListener mListener;
private final CallerIdentity mCallerIdentity;
- LinkedListener(@NonNull TListener listener, CallerIdentity callerIdentity) {
+ private IdentifiedListener(@NonNull TListener listener, CallerIdentity callerIdentity) {
mListener = listener;
mCallerIdentity = callerIdentity;
}
-
- @Override
- public void binderDied() {
- Log.d(mTag, "Remote Listener died: " + mListener);
- removeListener(mListener);
- }
}
private class HandlerRunnable implements Runnable {
- private final LinkedListener mLinkedListener;
+ private final IdentifiedListener mIdentifiedListener;
private final ListenerOperation<TListener> mOperation;
- HandlerRunnable(LinkedListener linkedListener, ListenerOperation<TListener> operation) {
- mLinkedListener = linkedListener;
+ private HandlerRunnable(IdentifiedListener identifiedListener,
+ ListenerOperation<TListener> operation) {
+ mIdentifiedListener = identifiedListener;
mOperation = operation;
}
@Override
public void run() {
try {
- mOperation.execute(mLinkedListener.mListener, mLinkedListener.mCallerIdentity);
+ mOperation.execute(mIdentifiedListener.mListener,
+ mIdentifiedListener.mCallerIdentity);
} catch (RemoteException e) {
Log.v(mTag, "Error in monitored listener.", e);
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
index 1f9b027be030..e7a71b99a213 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
@@ -20,6 +20,7 @@ import static android.security.keystore.recovery.KeyChainProtectionParams.TYPE_L
import android.annotation.Nullable;
import android.content.Context;
+import android.os.RemoteException;
import android.security.Scrypt;
import android.security.keystore.recovery.KeyChainProtectionParams;
import android.security.keystore.recovery.KeyChainSnapshot;
@@ -162,7 +163,7 @@ public class KeySyncTask implements Runnable {
}
}
- private void syncKeys() {
+ private void syncKeys() throws RemoteException {
if (mCredentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
// Application keys for the user will not be available for sync.
Log.w(TAG, "Credentials are not set for user " + mUserId);
@@ -195,7 +196,7 @@ public class KeySyncTask implements Runnable {
&& mCredentialType != LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
}
- private void syncKeysForAgent(int recoveryAgentUid) throws IOException {
+ private void syncKeysForAgent(int recoveryAgentUid) throws IOException, RemoteException {
boolean shouldRecreateCurrentVersion = false;
if (!shouldCreateSnapshot(recoveryAgentUid)) {
shouldRecreateCurrentVersion =
@@ -412,7 +413,7 @@ public class KeySyncTask implements Runnable {
private Map<String, Pair<SecretKey, byte[]>> getKeysToSync(int recoveryAgentUid)
throws InsecureUserException, KeyStoreException, UnrecoverableKeyException,
NoSuchAlgorithmException, NoSuchPaddingException, BadPlatformKeyException,
- InvalidKeyException, InvalidAlgorithmParameterException, IOException {
+ InvalidKeyException, InvalidAlgorithmParameterException, IOException, RemoteException {
PlatformDecryptionKey decryptKey = mPlatformKeyManager.getDecryptKey(mUserId);;
Map<String, WrappedKey> wrappedKeys = mRecoverableKeyStoreDb.getAllKeys(
mUserId, recoveryAgentUid, decryptKey.getGenerationId());
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
index 9ca052b9c9a8..1c187713540a 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
@@ -18,15 +18,21 @@ package com.android.server.locksettings.recoverablekeystore;
import android.app.KeyguardManager;
import android.content.Context;
+import android.os.RemoteException;
+import android.security.GateKeeper;
import android.security.keystore.AndroidKeyStoreSecretKey;
+import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
+import android.service.gatekeeper.IGateKeeperService;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb;
import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
@@ -34,9 +40,11 @@ import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Locale;
+import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
-import javax.security.auth.DestroyFailedException;
+import javax.crypto.spec.GCMParameterSpec;
/**
* Manages creating and checking the validity of the platform key.
@@ -67,6 +75,10 @@ public class PlatformKeyManager {
private static final String ENCRYPT_KEY_ALIAS_SUFFIX = "encrypt";
private static final String DECRYPT_KEY_ALIAS_SUFFIX = "decrypt";
private static final int USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS = 15;
+ private static final String KEY_WRAP_CIPHER_ALGORITHM = "AES/GCM/NoPadding";
+ private static final int GCM_TAG_LENGTH_BITS = 128;
+ // Only used for checking if a key is usable
+ private static final byte[] GCM_INSECURE_NONCE_BYTES = new byte[12];
private final Context mContext;
private final KeyStoreProxy mKeyStore;
@@ -158,12 +170,14 @@ public class PlatformKeyManager {
* @throws KeyStoreException if there is an error in AndroidKeyStore.
* @throws InsecureUserException if the user does not have a lock screen set.
* @throws IOException if there was an issue with local database update.
+ * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}.
*
* @hide
*/
@VisibleForTesting
void regenerate(int userId)
- throws NoSuchAlgorithmException, KeyStoreException, InsecureUserException, IOException {
+ throws NoSuchAlgorithmException, KeyStoreException, InsecureUserException, IOException,
+ RemoteException {
if (!isAvailable(userId)) {
throw new InsecureUserException(String.format(
Locale.US, "%d does not have a lock screen set.", userId));
@@ -190,11 +204,13 @@ public class PlatformKeyManager {
* @throws NoSuchAlgorithmException if AES is unavailable - should never occur.
* @throws InsecureUserException if the user does not have a lock screen set.
* @throws IOException if there was an issue with local database update.
+ * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}.
*
* @hide
*/
- public PlatformEncryptionKey getEncryptKey(int userId) throws KeyStoreException,
- UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException, IOException {
+ public PlatformEncryptionKey getEncryptKey(int userId)
+ throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException,
+ InsecureUserException, IOException, RemoteException {
init(userId);
try {
// Try to see if the decryption key is still accessible before using the encryption key.
@@ -243,14 +259,18 @@ public class PlatformKeyManager {
* @throws NoSuchAlgorithmException if AES is unavailable - should never occur.
* @throws InsecureUserException if the user does not have a lock screen set.
* @throws IOException if there was an issue with local database update.
+ * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}.
*
* @hide
*/
- public PlatformDecryptionKey getDecryptKey(int userId) throws KeyStoreException,
- UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException, IOException {
+ public PlatformDecryptionKey getDecryptKey(int userId)
+ throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException,
+ InsecureUserException, IOException, RemoteException {
init(userId);
try {
- return getDecryptKeyInternal(userId);
+ PlatformDecryptionKey decryptionKey = getDecryptKeyInternal(userId);
+ ensureDecryptionKeyIsValid(userId, decryptionKey);
+ return decryptionKey;
} catch (UnrecoverableKeyException e) {
Log.i(TAG, String.format(Locale.US,
"Regenerating permanently invalid Platform key for user %d.",
@@ -284,6 +304,29 @@ public class PlatformKeyManager {
}
/**
+ * Tries to use the decryption key to make sure it is not permanently invalidated. The exception
+ * {@code KeyPermanentlyInvalidatedException} is thrown only when the key is in use.
+ *
+ * <p>Note that we ignore all other InvalidKeyException exceptions, because such an exception
+ * may be thrown for auth-bound keys if there's no recent unlock event.
+ */
+ private void ensureDecryptionKeyIsValid(int userId, PlatformDecryptionKey decryptionKey)
+ throws UnrecoverableKeyException {
+ try {
+ Cipher.getInstance(KEY_WRAP_CIPHER_ALGORITHM).init(Cipher.UNWRAP_MODE,
+ decryptionKey.getKey(),
+ new GCMParameterSpec(GCM_TAG_LENGTH_BITS, GCM_INSECURE_NONCE_BYTES));
+ } catch (KeyPermanentlyInvalidatedException e) {
+ Log.e(TAG, String.format(Locale.US, "The platform key for user %d became invalid.",
+ userId));
+ throw new UnrecoverableKeyException(e.getMessage());
+ } catch (NoSuchAlgorithmException | InvalidKeyException
+ | InvalidAlgorithmParameterException | NoSuchPaddingException e) {
+ // Ignore all other exceptions
+ }
+ }
+
+ /**
* Initializes the class. If there is no current platform key, and the user has a lock screen
* set, will create the platform key and set the generation ID.
*
@@ -291,11 +334,13 @@ public class PlatformKeyManager {
* @throws KeyStoreException if there was an error in AndroidKeyStore.
* @throws NoSuchAlgorithmException if AES is unavailable - should never happen.
* @throws IOException if there was an issue with local database update.
+ * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}.
*
* @hide
*/
void init(int userId)
- throws KeyStoreException, NoSuchAlgorithmException, InsecureUserException, IOException {
+ throws KeyStoreException, NoSuchAlgorithmException, InsecureUserException, IOException,
+ RemoteException {
if (!isAvailable(userId)) {
throw new InsecureUserException(String.format(
Locale.US, "%d does not have a lock screen set.", userId));
@@ -372,6 +417,11 @@ public class PlatformKeyManager {
&& mKeyStore.containsAlias(getDecryptAlias(userId, generationId));
}
+ @VisibleForTesting
+ IGateKeeperService getGateKeeperService() {
+ return GateKeeper.getService();
+ }
+
/**
* Generates a new 256-bit AES key, and loads it into AndroidKeyStore with the given
* {@code generationId} determining its aliases.
@@ -380,15 +430,23 @@ public class PlatformKeyManager {
* available since API version 1.
* @throws KeyStoreException if there was an issue loading the keys into AndroidKeyStore.
* @throws IOException if there was an issue with local database update.
+ * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}.
*/
private void generateAndLoadKey(int userId, int generationId)
- throws NoSuchAlgorithmException, KeyStoreException, IOException {
+ throws NoSuchAlgorithmException, KeyStoreException, IOException, RemoteException {
String encryptAlias = getEncryptAlias(userId, generationId);
String decryptAlias = getDecryptAlias(userId, generationId);
// SecretKey implementation doesn't provide reliable way to destroy the secret
// so it may live in memory for some time.
SecretKey secretKey = generateAesKey();
+ long secureUserId = getGateKeeperService().getSecureUserId(userId);
+ // TODO(b/124095438): Propagate this failure instead of silently failing.
+ if (secureUserId == GateKeeper.INVALID_SECURE_USER_ID) {
+ Log.e(TAG, "No SID available for user " + userId);
+ return;
+ }
+
// Store decryption key first since it is more likely to fail.
mKeyStore.setEntry(
decryptAlias,
@@ -399,7 +457,7 @@ public class PlatformKeyManager {
USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
- .setBoundToSpecificSecureUserId(userId)
+ .setBoundToSpecificSecureUserId(secureUserId)
.build());
mKeyStore.setEntry(
encryptAlias,
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index b6ef180f4b59..b221241c25e2 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -1207,6 +1207,15 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
}
+ public void setPlaybackSpeed(String packageName, int pid, int uid,
+ ControllerCallbackLink caller, float speed) {
+ try {
+ mCb.notifySetPlaybackSpeed(packageName, pid, uid, caller, speed);
+ } catch (RuntimeException e) {
+ Slog.e(TAG, "Remote failure in setPlaybackSpeed.", e);
+ }
+ }
+
public void adjustVolume(String packageName, int pid, int uid,
ControllerCallbackLink caller, boolean asSystemService, int direction) {
try {
@@ -1446,6 +1455,13 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
@Override
+ public void setPlaybackSpeed(String packageName, ControllerCallbackLink caller,
+ float speed) {
+ mSessionCb.setPlaybackSpeed(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
+ caller, speed);
+ }
+
+ @Override
public void sendCustomAction(String packageName, ControllerCallbackLink caller,
String action, Bundle args) {
mSessionCb.sendCustomAction(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
diff --git a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
index 5c7317892f3f..62d9b20b636d 100644
--- a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
@@ -284,13 +284,16 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl {
* Tells the system UI that volume has changed on an active remote session.
*/
public void notifyRemoteVolumeChanged(int flags, MediaSessionRecord session) {
- if (mRvc == null || !session.isActive()) {
- return;
- }
- try {
- mRvc.remoteVolumeChanged(session.getSessionToken(), flags);
- } catch (Exception e) {
- Log.wtf(TAG, "Error sending volume change to system UI.", e);
+ synchronized (mLock) {
+ if (mRvc == null || !session.isActive()) {
+ return;
+ }
+ try {
+ mRvc.remoteVolumeChanged(session.getSessionToken(), flags);
+ } catch (Exception e) {
+ Log.w(TAG, "Error sending volume change to system UI.", e);
+ mRvc = null;
+ }
}
}
@@ -563,7 +566,7 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl {
String callerPackageName, SessionCallbackLink cb, String tag) {
FullUserRecord user = getFullUserRecordLocked(userId);
if (user == null) {
- Log.wtf(TAG, "Request from invalid user: " + userId);
+ Log.w(TAG, "Request from invalid user: " + userId + ", pkg=" + callerPackageName);
throw new RuntimeException("Session request from invalid user.");
}
@@ -643,7 +646,8 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl {
MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId);
mRvc.updateRemoteController(record == null ? null : record.getSessionToken());
} catch (RemoteException e) {
- Log.wtf(TAG, "Error sending default remote volume to sys ui.", e);
+ Log.w(TAG, "Error sending default remote volume to sys ui.", e);
+ mRvc = null;
}
}
}
@@ -1661,7 +1665,9 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl {
final long token = Binder.clearCallingIdentity();
try {
enforceSystemUiPermission("listen for volume changes", pid, uid);
- mRvc = rvc;
+ synchronized (mLock) {
+ mRvc = rvc;
+ }
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 9e5b92a6b944..3f15b381c18b 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -17,9 +17,6 @@
package com.android.server.net;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NONE;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
import static android.provider.Settings.ACTION_VPN_SETTINGS;
import android.app.Notification;
@@ -30,17 +27,14 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
-import android.net.LinkProperties;
import android.net.LinkAddress;
+import android.net.LinkProperties;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkInfo.State;
-import android.net.NetworkPolicyManager;
import android.os.INetworkManagementService;
-import android.os.RemoteException;
import android.security.Credentials;
import android.security.KeyStore;
-import android.system.Os;
import android.text.TextUtils;
import android.util.Slog;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
index 4bd8f450c76b..6d82c1c257ab 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -15,15 +15,15 @@
*/
package com.android.server.net;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
+import static android.net.INetd.FIREWALL_CHAIN_DOZABLE;
+import static android.net.INetd.FIREWALL_CHAIN_POWERSAVE;
+import static android.net.INetd.FIREWALL_CHAIN_STANDBY;
+import static android.net.INetd.FIREWALL_RULE_ALLOW;
+import static android.net.INetd.FIREWALL_RULE_DENY;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
import android.app.ActivityManager;
import android.net.NetworkPolicyManager;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index af55605975ca..75b62cb349af 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -38,6 +38,11 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLE
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.INetd.FIREWALL_CHAIN_DOZABLE;
+import static android.net.INetd.FIREWALL_CHAIN_POWERSAVE;
+import static android.net.INetd.FIREWALL_CHAIN_STANDBY;
+import static android.net.INetd.FIREWALL_RULE_ALLOW;
+import static android.net.INetd.FIREWALL_RULE_DENY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -45,12 +50,7 @@ import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS;
import static android.net.NetworkPolicyManager.MASK_METERED_NETWORKS;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index a7f114655dcb..e479a1539e25 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -23,6 +23,9 @@ import static android.content.Intent.ACTION_PACKAGE_REMOVED;
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.pm.PackageManager.SIGNATURE_MATCH;
+import static android.os.Trace.TRACE_TAG_RRO;
+import static android.os.Trace.traceBegin;
+import static android.os.Trace.traceEnd;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -223,36 +226,41 @@ public final class OverlayManagerService extends SystemService {
public OverlayManagerService(@NonNull final Context context,
@NonNull final Installer installer) {
super(context);
- mSettingsFile = new AtomicFile(
- new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays");
- mPackageManager = new PackageManagerHelper();
- mUserManager = UserManagerService.getInstance();
- IdmapManager im = new IdmapManager(installer);
- mSettings = new OverlayManagerSettings();
- mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
- getDefaultOverlayPackages(), new OverlayChangeListener());
-
- final IntentFilter packageFilter = new IntentFilter();
- packageFilter.addAction(ACTION_PACKAGE_ADDED);
- packageFilter.addAction(ACTION_PACKAGE_CHANGED);
- packageFilter.addAction(ACTION_PACKAGE_REMOVED);
- packageFilter.addDataScheme("package");
- getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL,
- packageFilter, null, null);
-
- final IntentFilter userFilter = new IntentFilter();
- userFilter.addAction(ACTION_USER_ADDED);
- userFilter.addAction(ACTION_USER_REMOVED);
- getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
- userFilter, null, null);
-
- restoreSettings();
-
- initIfNeeded();
- onSwitchUser(UserHandle.USER_SYSTEM);
-
- publishBinderService(Context.OVERLAY_SERVICE, mService);
- publishLocalService(OverlayManagerService.class, this);
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS#OverlayManagerService");
+ mSettingsFile = new AtomicFile(
+ new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays");
+ mPackageManager = new PackageManagerHelper();
+ mUserManager = UserManagerService.getInstance();
+ IdmapManager im = new IdmapManager(installer);
+ mSettings = new OverlayManagerSettings();
+ mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
+ getDefaultOverlayPackages(), new OverlayChangeListener());
+
+ final IntentFilter packageFilter = new IntentFilter();
+ packageFilter.addAction(ACTION_PACKAGE_ADDED);
+ packageFilter.addAction(ACTION_PACKAGE_CHANGED);
+ packageFilter.addAction(ACTION_PACKAGE_REMOVED);
+ packageFilter.addDataScheme("package");
+ getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL,
+ packageFilter, null, null);
+
+ final IntentFilter userFilter = new IntentFilter();
+ userFilter.addAction(ACTION_USER_ADDED);
+ userFilter.addAction(ACTION_USER_REMOVED);
+ getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
+ userFilter, null, null);
+
+ restoreSettings();
+
+ initIfNeeded();
+ onSwitchUser(UserHandle.USER_SYSTEM);
+
+ publishBinderService(Context.OVERLAY_SERVICE, mService);
+ publishLocalService(OverlayManagerService.class, this);
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
+ }
}
@Override
@@ -280,13 +288,18 @@ public final class OverlayManagerService extends SystemService {
@Override
public void onSwitchUser(final int newUserId) {
- // ensure overlays in the settings are up-to-date, and propagate
- // any asset changes to the rest of the system
- synchronized (mLock) {
- final List<String> targets = mImpl.updateOverlaysForUser(newUserId);
- updateAssets(newUserId, targets);
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS#onSwitchUser " + newUserId);
+ // ensure overlays in the settings are up-to-date, and propagate
+ // any asset changes to the rest of the system
+ synchronized (mLock) {
+ final List<String> targets = mImpl.updateOverlaysForUser(newUserId);
+ updateAssets(newUserId, targets);
+ }
+ schedulePersistSettings();
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
}
- schedulePersistSettings();
}
private static String[] getDefaultOverlayPackages() {
@@ -350,85 +363,110 @@ public final class OverlayManagerService extends SystemService {
private void onPackageAdded(@NonNull final String packageName,
@NonNull final int[] userIds) {
- for (final int userId : userIds) {
- synchronized (mLock) {
- final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
- false);
- if (pi != null) {
- mPackageManager.cachePackageInfo(packageName, userId, pi);
- if (pi.isOverlayPackage()) {
- mImpl.onOverlayPackageAdded(packageName, userId);
- } else {
- mImpl.onTargetPackageAdded(packageName, userId);
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS#onPackageAdded " + packageName);
+ for (final int userId : userIds) {
+ synchronized (mLock) {
+ final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
+ false);
+ if (pi != null) {
+ mPackageManager.cachePackageInfo(packageName, userId, pi);
+ if (pi.isOverlayPackage()) {
+ mImpl.onOverlayPackageAdded(packageName, userId);
+ } else {
+ mImpl.onTargetPackageAdded(packageName, userId);
+ }
}
}
}
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
}
}
private void onPackageChanged(@NonNull final String packageName,
@NonNull final int[] userIds) {
- for (int userId : userIds) {
- synchronized (mLock) {
- final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
- false);
- if (pi != null) {
- mPackageManager.cachePackageInfo(packageName, userId, pi);
- if (pi.isOverlayPackage()) {
- mImpl.onOverlayPackageChanged(packageName, userId);
- } else {
- mImpl.onTargetPackageChanged(packageName, userId);
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS#onPackageChanged " + packageName);
+ for (int userId : userIds) {
+ synchronized (mLock) {
+ final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
+ false);
+ if (pi != null) {
+ mPackageManager.cachePackageInfo(packageName, userId, pi);
+ if (pi.isOverlayPackage()) {
+ mImpl.onOverlayPackageChanged(packageName, userId);
+ } else {
+ mImpl.onTargetPackageChanged(packageName, userId);
+ }
}
}
}
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
}
}
private void onPackageUpgrading(@NonNull final String packageName,
@NonNull final int[] userIds) {
- for (int userId : userIds) {
- synchronized (mLock) {
- mPackageManager.forgetPackageInfo(packageName, userId);
- final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
- if (oi != null) {
- mImpl.onOverlayPackageUpgrading(packageName, userId);
- } else {
- mImpl.onTargetPackageUpgrading(packageName, userId);
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS#onPackageUpgrading " + packageName);
+ for (int userId : userIds) {
+ synchronized (mLock) {
+ mPackageManager.forgetPackageInfo(packageName, userId);
+ final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
+ if (oi != null) {
+ mImpl.onOverlayPackageUpgrading(packageName, userId);
+ } else {
+ mImpl.onTargetPackageUpgrading(packageName, userId);
+ }
}
}
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
}
}
private void onPackageUpgraded(@NonNull final String packageName,
@NonNull final int[] userIds) {
- for (int userId : userIds) {
- synchronized (mLock) {
- final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
- false);
- if (pi != null) {
- mPackageManager.cachePackageInfo(packageName, userId, pi);
- if (pi.isOverlayPackage()) {
- mImpl.onOverlayPackageUpgraded(packageName, userId);
- } else {
- mImpl.onTargetPackageUpgraded(packageName, userId);
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS#onPackageUpgraded " + packageName);
+ for (int userId : userIds) {
+ synchronized (mLock) {
+ final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
+ false);
+ if (pi != null) {
+ mPackageManager.cachePackageInfo(packageName, userId, pi);
+ if (pi.isOverlayPackage()) {
+ mImpl.onOverlayPackageUpgraded(packageName, userId);
+ } else {
+ mImpl.onTargetPackageUpgraded(packageName, userId);
+ }
}
}
}
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
}
}
private void onPackageRemoved(@NonNull final String packageName,
@NonNull final int[] userIds) {
- for (int userId : userIds) {
- synchronized (mLock) {
- mPackageManager.forgetPackageInfo(packageName, userId);
- final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
- if (oi != null) {
- mImpl.onOverlayPackageRemoved(packageName, userId);
- } else {
- mImpl.onTargetPackageRemoved(packageName, userId);
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS#onPackageRemoved " + packageName);
+ for (int userId : userIds) {
+ synchronized (mLock) {
+ mPackageManager.forgetPackageInfo(packageName, userId);
+ final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
+ if (oi != null) {
+ mImpl.onOverlayPackageRemoved(packageName, userId);
+ } else {
+ mImpl.onTargetPackageRemoved(packageName, userId);
+ }
}
}
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
}
}
}
@@ -440,19 +478,29 @@ public final class OverlayManagerService extends SystemService {
switch (intent.getAction()) {
case ACTION_USER_ADDED:
if (userId != UserHandle.USER_NULL) {
- final ArrayList<String> targets;
- synchronized (mLock) {
- targets = mImpl.updateOverlaysForUser(userId);
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS ACTION_USER_ADDED");
+ final ArrayList<String> targets;
+ synchronized (mLock) {
+ targets = mImpl.updateOverlaysForUser(userId);
+ }
+ updateOverlayPaths(userId, targets);
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
}
- updateOverlayPaths(userId, targets);
}
break;
case ACTION_USER_REMOVED:
if (userId != UserHandle.USER_NULL) {
- synchronized (mLock) {
- mImpl.onUserRemoved(userId);
- mPackageManager.forgetAllPackageInfos(userId);
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS ACTION_USER_REMOVED");
+ synchronized (mLock) {
+ mImpl.onUserRemoved(userId);
+ mPackageManager.forgetAllPackageInfos(userId);
+ }
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
}
}
break;
@@ -466,152 +514,198 @@ public final class OverlayManagerService extends SystemService {
private final IBinder mService = new IOverlayManager.Stub() {
@Override
public Map<String, List<OverlayInfo>> getAllOverlays(int userId) throws RemoteException {
- userId = handleIncomingUser(userId, "getAllOverlays");
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS#getAllOverlays " + userId);
+ userId = handleIncomingUser(userId, "getAllOverlays");
- synchronized (mLock) {
- return mImpl.getOverlaysForUser(userId);
+ synchronized (mLock) {
+ return mImpl.getOverlaysForUser(userId);
+ }
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
}
}
@Override
public List<OverlayInfo> getOverlayInfosForTarget(@Nullable final String targetPackageName,
int userId) throws RemoteException {
- userId = handleIncomingUser(userId, "getOverlayInfosForTarget");
- if (targetPackageName == null) {
- return Collections.emptyList();
- }
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS#getOverlayInfosForTarget " + targetPackageName);
+ userId = handleIncomingUser(userId, "getOverlayInfosForTarget");
+ if (targetPackageName == null) {
+ return Collections.emptyList();
+ }
- synchronized (mLock) {
- return mImpl.getOverlayInfosForTarget(targetPackageName, userId);
+ synchronized (mLock) {
+ return mImpl.getOverlayInfosForTarget(targetPackageName, userId);
+ }
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
}
}
@Override
public OverlayInfo getOverlayInfo(@Nullable final String packageName,
int userId) throws RemoteException {
- userId = handleIncomingUser(userId, "getOverlayInfo");
- if (packageName == null) {
- return null;
- }
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS#getOverlayInfo " + packageName);
+ userId = handleIncomingUser(userId, "getOverlayInfo");
+ if (packageName == null) {
+ return null;
+ }
- synchronized (mLock) {
- return mImpl.getOverlayInfo(packageName, userId);
+ synchronized (mLock) {
+ return mImpl.getOverlayInfo(packageName, userId);
+ }
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
}
}
@Override
public boolean setEnabled(@Nullable final String packageName, final boolean enable,
int userId) throws RemoteException {
- enforceChangeOverlayPackagesPermission("setEnabled");
- userId = handleIncomingUser(userId, "setEnabled");
- if (packageName == null) {
- return false;
- }
-
- final long ident = Binder.clearCallingIdentity();
try {
- synchronized (mLock) {
- return mImpl.setEnabled(packageName, enable, userId);
+ traceBegin(TRACE_TAG_RRO, "OMS#setEnabled " + packageName + " " + enable);
+ enforceChangeOverlayPackagesPermission("setEnabled");
+ userId = handleIncomingUser(userId, "setEnabled");
+ if (packageName == null) {
+ return false;
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ return mImpl.setEnabled(packageName, enable, userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
} finally {
- Binder.restoreCallingIdentity(ident);
+ traceEnd(TRACE_TAG_RRO);
}
}
@Override
public boolean setEnabledExclusive(@Nullable final String packageName, final boolean enable,
int userId) throws RemoteException {
- enforceChangeOverlayPackagesPermission("setEnabledExclusive");
- userId = handleIncomingUser(userId, "setEnabledExclusive");
- if (packageName == null || !enable) {
- return false;
- }
-
- final long ident = Binder.clearCallingIdentity();
try {
- synchronized (mLock) {
- return mImpl.setEnabledExclusive(packageName, false /* withinCategory */,
- userId);
+ traceBegin(TRACE_TAG_RRO, "OMS#setEnabledExclusive " + packageName + " " + enable);
+ enforceChangeOverlayPackagesPermission("setEnabledExclusive");
+ userId = handleIncomingUser(userId, "setEnabledExclusive");
+ if (packageName == null || !enable) {
+ return false;
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ return mImpl.setEnabledExclusive(packageName, false /* withinCategory */,
+ userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
} finally {
- Binder.restoreCallingIdentity(ident);
+ traceEnd(TRACE_TAG_RRO);
}
}
@Override
public boolean setEnabledExclusiveInCategory(@Nullable String packageName, int userId)
throws RemoteException {
- enforceChangeOverlayPackagesPermission("setEnabledExclusiveInCategory");
- userId = handleIncomingUser(userId, "setEnabledExclusiveInCategory");
- if (packageName == null) {
- return false;
- }
-
- final long ident = Binder.clearCallingIdentity();
try {
- synchronized (mLock) {
- return mImpl.setEnabledExclusive(packageName, true /* withinCategory */,
- userId);
+ traceBegin(TRACE_TAG_RRO, "OMS#setEnabledExclusiveInCategory " + packageName);
+ enforceChangeOverlayPackagesPermission("setEnabledExclusiveInCategory");
+ userId = handleIncomingUser(userId, "setEnabledExclusiveInCategory");
+ if (packageName == null) {
+ return false;
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ return mImpl.setEnabledExclusive(packageName, true /* withinCategory */,
+ userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
} finally {
- Binder.restoreCallingIdentity(ident);
+ traceEnd(TRACE_TAG_RRO);
}
}
@Override
public boolean setPriority(@Nullable final String packageName,
@Nullable final String parentPackageName, int userId) throws RemoteException {
- enforceChangeOverlayPackagesPermission("setPriority");
- userId = handleIncomingUser(userId, "setPriority");
- if (packageName == null || parentPackageName == null) {
- return false;
- }
-
- final long ident = Binder.clearCallingIdentity();
try {
- synchronized (mLock) {
- return mImpl.setPriority(packageName, parentPackageName, userId);
+ traceBegin(TRACE_TAG_RRO, "OMS#setPriority " + packageName + " "
+ + parentPackageName);
+ enforceChangeOverlayPackagesPermission("setPriority");
+ userId = handleIncomingUser(userId, "setPriority");
+ if (packageName == null || parentPackageName == null) {
+ return false;
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ return mImpl.setPriority(packageName, parentPackageName, userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
} finally {
- Binder.restoreCallingIdentity(ident);
+ traceEnd(TRACE_TAG_RRO);
}
}
@Override
public boolean setHighestPriority(@Nullable final String packageName, int userId)
throws RemoteException {
- enforceChangeOverlayPackagesPermission("setHighestPriority");
- userId = handleIncomingUser(userId, "setHighestPriority");
- if (packageName == null) {
- return false;
- }
-
- final long ident = Binder.clearCallingIdentity();
try {
- synchronized (mLock) {
- return mImpl.setHighestPriority(packageName, userId);
+ traceBegin(TRACE_TAG_RRO, "OMS#setHighestPriority " + packageName);
+ enforceChangeOverlayPackagesPermission("setHighestPriority");
+ userId = handleIncomingUser(userId, "setHighestPriority");
+ if (packageName == null) {
+ return false;
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ return mImpl.setHighestPriority(packageName, userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
} finally {
- Binder.restoreCallingIdentity(ident);
+ traceEnd(TRACE_TAG_RRO);
}
}
@Override
public boolean setLowestPriority(@Nullable final String packageName, int userId)
throws RemoteException {
- enforceChangeOverlayPackagesPermission("setLowestPriority");
- userId = handleIncomingUser(userId, "setLowestPriority");
- if (packageName == null) {
- return false;
- }
-
- final long ident = Binder.clearCallingIdentity();
try {
- synchronized (mLock) {
- return mImpl.setLowestPriority(packageName, userId);
+ traceBegin(TRACE_TAG_RRO, "OMS#setLowestPriority " + packageName);
+ enforceChangeOverlayPackagesPermission("setLowestPriority");
+ userId = handleIncomingUser(userId, "setLowestPriority");
+ if (packageName == null) {
+ return false;
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ return mImpl.setLowestPriority(packageName, userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
} finally {
- Binder.restoreCallingIdentity(ident);
+ traceEnd(TRACE_TAG_RRO);
}
}
@@ -705,45 +799,52 @@ public final class OverlayManagerService extends SystemService {
* Updates the target packages' set of enabled overlays in PackageManager.
*/
private void updateOverlayPaths(int userId, List<String> targetPackageNames) {
- if (DEBUG) {
- Slog.d(TAG, "Updating overlay assets");
- }
- final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
- final boolean updateFrameworkRes = targetPackageNames.contains("android");
- if (updateFrameworkRes) {
- targetPackageNames = pm.getTargetPackageNames(userId);
- }
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS#updateOverlayPaths " + targetPackageNames);
+ if (DEBUG) {
+ Slog.d(TAG, "Updating overlay assets");
+ }
+ final PackageManagerInternal pm =
+ LocalServices.getService(PackageManagerInternal.class);
+ final boolean updateFrameworkRes = targetPackageNames.contains("android");
+ if (updateFrameworkRes) {
+ targetPackageNames = pm.getTargetPackageNames(userId);
+ }
+
+ final Map<String, List<String>> pendingChanges =
+ new ArrayMap<>(targetPackageNames.size());
+ synchronized (mLock) {
+ final List<String> frameworkOverlays =
+ mImpl.getEnabledOverlayPackageNames("android", userId);
+ final int n = targetPackageNames.size();
+ for (int i = 0; i < n; i++) {
+ final String targetPackageName = targetPackageNames.get(i);
+ List<String> list = new ArrayList<>();
+ if (!"android".equals(targetPackageName)) {
+ list.addAll(frameworkOverlays);
+ }
+ list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
+ pendingChanges.put(targetPackageName, list);
+ }
+ }
- final Map<String, List<String>> pendingChanges = new ArrayMap<>(targetPackageNames.size());
- synchronized (mLock) {
- final List<String> frameworkOverlays =
- mImpl.getEnabledOverlayPackageNames("android", userId);
final int n = targetPackageNames.size();
for (int i = 0; i < n; i++) {
final String targetPackageName = targetPackageNames.get(i);
- List<String> list = new ArrayList<>();
- if (!"android".equals(targetPackageName)) {
- list.addAll(frameworkOverlays);
+ if (DEBUG) {
+ Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=["
+ + TextUtils.join(",", pendingChanges.get(targetPackageName))
+ + "] userId=" + userId);
}
- list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
- pendingChanges.put(targetPackageName, list);
- }
- }
-
- final int n = targetPackageNames.size();
- for (int i = 0; i < n; i++) {
- final String targetPackageName = targetPackageNames.get(i);
- if (DEBUG) {
- Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=["
- + TextUtils.join(",", pendingChanges.get(targetPackageName))
- + "] userId=" + userId);
- }
- if (!pm.setEnabledOverlayPackages(
- userId, targetPackageName, pendingChanges.get(targetPackageName))) {
- Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
- targetPackageName, userId));
+ if (!pm.setEnabledOverlayPackages(
+ userId, targetPackageName, pendingChanges.get(targetPackageName))) {
+ Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
+ targetPackageName, userId));
+ }
}
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
}
}
@@ -785,32 +886,37 @@ public final class OverlayManagerService extends SystemService {
}
private void restoreSettings() {
- synchronized (mLock) {
- if (!mSettingsFile.getBaseFile().exists()) {
- return;
- }
- try (FileInputStream stream = mSettingsFile.openRead()) {
- mSettings.restore(stream);
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS#restoreSettings");
+ synchronized (mLock) {
+ if (!mSettingsFile.getBaseFile().exists()) {
+ return;
+ }
+ try (FileInputStream stream = mSettingsFile.openRead()) {
+ mSettings.restore(stream);
- // We might have data for dying users if the device was
- // restarted before we received USER_REMOVED. Remove data for
- // users that will not exist after the system is ready.
+ // We might have data for dying users if the device was
+ // restarted before we received USER_REMOVED. Remove data for
+ // users that will not exist after the system is ready.
- final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/);
- final int[] liveUserIds = new int[liveUsers.size()];
- for (int i = 0; i < liveUsers.size(); i++) {
- liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier();
- }
- Arrays.sort(liveUserIds);
+ final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/);
+ final int[] liveUserIds = new int[liveUsers.size()];
+ for (int i = 0; i < liveUsers.size(); i++) {
+ liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier();
+ }
+ Arrays.sort(liveUserIds);
- for (int userId : mSettings.getUsers()) {
- if (Arrays.binarySearch(liveUserIds, userId) < 0) {
- mSettings.removeUser(userId);
+ for (int userId : mSettings.getUsers()) {
+ if (Arrays.binarySearch(liveUserIds, userId) < 0) {
+ mSettings.removeUser(userId);
+ }
}
+ } catch (IOException | XmlPullParserException e) {
+ Slog.e(TAG, "failed to restore overlay state", e);
}
- } catch (IOException | XmlPullParserException e) {
- Slog.e(TAG, "failed to restore overlay state", e);
}
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
}
}
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
new file mode 100644
index 000000000000..dac4b6ff39c3
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.s
+ */
+
+package com.android.server.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.apex.ApexInfo;
+import android.apex.ApexInfoList;
+import android.apex.ApexSessionInfo;
+import android.apex.IApexService;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.PackageParserException;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Slog;
+
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * ApexManager class handles communications with the apex service to perform operation and queries,
+ * as well as providing caching to avoid unnecessary calls to the service.
+ */
+class ApexManager {
+ static final String TAG = "ApexManager";
+ private final IApexService mApexService;
+ private final Map<String, PackageInfo> mActivePackagesCache;
+
+ ApexManager() {
+ mApexService = IApexService.Stub.asInterface(
+ ServiceManager.getService("apexservice"));
+ mActivePackagesCache = populateActivePackagesCache();
+ }
+
+ @NonNull
+ private Map<String, PackageInfo> populateActivePackagesCache() {
+ try {
+ List<PackageInfo> list = new ArrayList<>();
+ final ApexInfo[] activePkgs = mApexService.getActivePackages();
+ for (ApexInfo ai : activePkgs) {
+ // If the device is using flattened APEX, don't report any APEX
+ // packages since they won't be managed or updated by PackageManager.
+ if ((new File(ai.packagePath)).isDirectory()) {
+ break;
+ }
+ try {
+ list.add(PackageParser.generatePackageInfoFromApex(
+ new File(ai.packagePath), true /* collect certs */));
+ } catch (PackageParserException pe) {
+ throw new IllegalStateException("Unable to parse: " + ai, pe);
+ }
+ }
+ return list.stream().collect(Collectors.toMap(p -> p.packageName, Function.identity()));
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
+ throw new RuntimeException(re);
+ }
+ }
+
+ /**
+ * Retrieves information about an active APEX package.
+ *
+ * @param packageName the package name to look for. Note that this is the package name reported
+ * in the APK container manifest (i.e. AndroidManifest.xml), which might
+ * differ from the one reported in the APEX manifest (i.e.
+ * apex_manifest.json).
+ * @return a PackageInfo object with the information about the package, or null if the package
+ * is not found.
+ */
+ @Nullable PackageInfo getActivePackage(String packageName) {
+ return mActivePackagesCache.get(packageName);
+ }
+
+ /**
+ * Retrieves information about all active APEX packages.
+ *
+ * @return a Collection of PackageInfo object, each one containing information about a different
+ * active package.
+ */
+ Collection<PackageInfo> getActivePackages() {
+ return mActivePackagesCache.values();
+ }
+
+ /**
+ * Retrieves information about an apexd staged session i.e. the internal state used by apexd to
+ * track the different states of a session.
+ *
+ * @param sessionId the identifier of the session.
+ * @return an ApexSessionInfo object, or null if the session is not known.
+ */
+ @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) {
+ try {
+ ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId);
+ if (apexSessionInfo.isUnknown) {
+ return null;
+ }
+ return apexSessionInfo;
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Unable to contact apexservice", re);
+ throw new RuntimeException(re);
+ }
+ }
+
+ /**
+ * Submit a staged session to apex service. This causes the apex service to perform some initial
+ * verification and accept or reject the session. Submitting a session successfully is not
+ * enough for it to be activated at the next boot, the caller needs to call
+ * {@link #markStagedSessionReady(int)}.
+ *
+ * @param sessionId the identifier of the {@link PackageInstallerSession} being submitted.
+ * @param childSessionIds if {@code sessionId} is a multi-package session, this should contain
+ * an array of identifiers of all the child sessions. Otherwise it should
+ * be an empty array.
+ * @param apexInfoList this is an output parameter, which needs to be initialized by tha caller
+ * and will be filled with a list of {@link ApexInfo} objects, each of which
+ * contains metadata about one of the packages being submitted as part of
+ * the session.
+ * @return whether the submission of the session was successful.
+ */
+ boolean submitStagedSession(
+ int sessionId, @NonNull int[] childSessionIds, @NonNull ApexInfoList apexInfoList) {
+ try {
+ return mApexService.submitStagedSession(sessionId, childSessionIds, apexInfoList);
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Unable to contact apexservice", re);
+ throw new RuntimeException(re);
+ }
+ }
+
+ /**
+ * Mark a staged session previously submitted using {@cde submitStagedSession} as ready to be
+ * applied at next reboot.
+ *
+ * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as ready.
+ * @return true upon success, false if the session is unknown.
+ */
+ boolean markStagedSessionReady(int sessionId) {
+ try {
+ return mApexService.markStagedSessionReady(sessionId);
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Unable to contact apexservice", re);
+ throw new RuntimeException(re);
+ }
+ }
+
+ /**
+ * Dumps various state information to the provided {@link PrintWriter} object.
+ *
+ * @param pw the {@link PrintWriter} object to send information to.
+ * @param packageName a {@link String} containing a package name, or {@code null}. If set, only
+ * information about that specific package will be dumped.
+ */
+ void dump(PrintWriter pw, @Nullable String packageName) {
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
+ ipw.println();
+ ipw.println("Active APEX packages:");
+ ipw.increaseIndent();
+ try {
+ populateActivePackagesCache();
+ for (PackageInfo pi : mActivePackagesCache.values()) {
+ if (packageName != null && !packageName.equals(pi.packageName)) {
+ continue;
+ }
+ ipw.println(pi.packageName);
+ ipw.increaseIndent();
+ ipw.println("Version: " + pi.versionCode);
+ ipw.println("Path: " + pi.applicationInfo.sourceDir);
+ ipw.decreaseIndent();
+ }
+ ipw.decreaseIndent();
+ ipw.println();
+ ipw.println("APEX session state:");
+ ipw.increaseIndent();
+ final ApexSessionInfo[] sessions = mApexService.getSessions();
+ for (ApexSessionInfo si : sessions) {
+ ipw.println("Session ID: " + Integer.toString(si.sessionId));
+ ipw.increaseIndent();
+ if (si.isUnknown) {
+ ipw.println("State: UNKNOWN");
+ } else if (si.isVerified) {
+ ipw.println("State: VERIFIED");
+ } else if (si.isStaged) {
+ ipw.println("State: STAGED");
+ } else if (si.isActivated) {
+ ipw.println("State: ACTIVATED");
+ } else if (si.isActivationPendingRetry) {
+ ipw.println("State: ACTIVATION PENDING RETRY");
+ } else if (si.isActivationFailed) {
+ ipw.println("State: ACTIVATION FAILED");
+ }
+ ipw.decreaseIndent();
+ }
+ ipw.decreaseIndent();
+ } catch (RemoteException e) {
+ ipw.println("Couldn't communicate with apexd.");
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 21965e4e83a2..86083494f3d6 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -186,7 +186,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
};
- public PackageInstallerService(Context context, PackageManagerService pm) {
+ public PackageInstallerService(Context context, PackageManagerService pm, ApexManager am) {
mContext = context;
mPm = pm;
mPermissionManager = LocalServices.getService(PermissionManagerInternal.class);
@@ -204,7 +204,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions");
mSessionsDir.mkdirs();
- mStagingManager = new StagingManager(pm, this);
+ mStagingManager = new StagingManager(pm, this, am);
}
private void setBootCompleted() {
@@ -481,6 +481,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
}
+ if (params.isStaged) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, TAG);
+ }
+
if (!params.isMultiPackage) {
// Only system components can circumvent runtime permissions when installing.
if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index eaedec597359..61a1a2f81101 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -119,13 +119,11 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.apex.ApexInfo;
-import android.apex.ApexSessionInfo;
-import android.apex.IApexService;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppDetailsActivity;
import android.app.AppOpsManager;
+import android.app.BroadcastOptions;
import android.app.IActivityManager;
import android.app.ResourcesManager;
import android.app.admin.IDevicePolicyManager;
@@ -241,6 +239,7 @@ import android.os.storage.StorageManagerInternal;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
import android.permission.PermissionControllerManager;
+import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
@@ -733,10 +732,10 @@ public class PackageManagerService extends IPackageManager.Stub
@GuardedBy("mPackages")
final private ArraySet<PackageListObserver> mPackageListObservers = new ArraySet<>();
- private PackageManager mPackageManager;
-
private final ModuleInfoProvider mModuleInfoProvider;
+ private final ApexManager mApexManager;
+
class PackageParserCallback implements PackageParser.Callback {
@Override public final boolean hasFeature(String feature) {
return PackageManagerService.this.hasSystemFeature(feature, 0);
@@ -986,6 +985,9 @@ public class PackageManagerService extends IPackageManager.Stub
@GuardedBy("mPackages")
private PackageManagerInternal.DefaultBrowserProvider mDefaultBrowserProvider;
+ @GuardedBy("mPackages")
+ private PackageManagerInternal.DefaultHomeProvider mDefaultHomeProvider;
+
private class IntentVerifierProxy implements IntentFilterVerifier<ActivityIntentInfo> {
private Context mContext;
private ComponentName mIntentFilterVerifierComponent;
@@ -1046,12 +1048,17 @@ public class PackageManagerService extends IPackageManager.Stub
verificationIntent.setComponent(mIntentFilterVerifierComponent);
verificationIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ final long whitelistTimeout = getVerificationTimeout();
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setTemporaryAppWhitelistDuration(whitelistTimeout);
+
DeviceIdleController.LocalService idleController = getDeviceIdleController();
idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
- mIntentFilterVerifierComponent.getPackageName(), getVerificationTimeout(),
+ mIntentFilterVerifierComponent.getPackageName(), whitelistTimeout,
UserHandle.USER_SYSTEM, true, "intent filter verifier");
- mContext.sendBroadcastAsUser(verificationIntent, UserHandle.SYSTEM);
+ mContext.sendBroadcastAsUser(verificationIntent, UserHandle.SYSTEM,
+ null, options.toBundle());
if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
"Sending IntentFilter verification broadcast");
}
@@ -1345,7 +1352,7 @@ public class PackageManagerService extends IPackageManager.Stub
final @Nullable String mRequiredVerifierPackage;
final @NonNull String mRequiredInstallerPackage;
final @NonNull String mRequiredUninstallerPackage;
- final String mRequiredPermissionControllerPackage;
+ final @NonNull String mRequiredPermissionControllerPackage;
final @Nullable String mSetupWizardPackage;
final @Nullable String mStorageManagerPackage;
final @Nullable String mSystemTextClassifierPackage;
@@ -1936,6 +1943,10 @@ public class PackageManagerService extends IPackageManager.Stub
// We may also need to apply pending (restored) runtime
// permission grants within these users.
mSettings.applyPendingPermissionGrantsLPw(packageName, userId);
+
+ // Persistent preferred activity might have came into effect due to this
+ // install.
+ updateDefaultHomeLPw(userId);
}
}
}
@@ -3074,7 +3085,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- mInstallerService = new PackageInstallerService(context, this);
+ mApexManager = new ApexManager();
+ mInstallerService = new PackageInstallerService(context, this, mApexManager);
final Pair<ComponentName, String> instantAppResolverComponent =
getInstantAppResolverLPr();
if (instantAppResolverComponent != null) {
@@ -3301,7 +3313,8 @@ public class PackageManagerService extends IPackageManager.Stub
// feature flags should cause us to invalidate any caches.
final String cacheName = SystemProperties.digestOf(
"ro.build.fingerprint",
- "persist.sys.isolated_storage");
+ StorageManager.PROP_ISOLATED_STORAGE,
+ StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT);
// Reconcile cache directories, keeping only what we'd actually use.
for (File cacheDir : FileUtils.listFilesOrEmpty(cacheBaseDir)) {
@@ -3934,27 +3947,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
//
if (!matchFactoryOnly && (flags & MATCH_APEX) != 0) {
- //TODO(b/123052859) Don't do file operations every time there is a query.
- final IApexService apex = IApexService.Stub.asInterface(
- ServiceManager.getService("apexservice"));
- if (apex != null) {
- try {
- final ApexInfo activePkg = apex.getActivePackage(packageName);
- if (activePkg != null && !TextUtils.isEmpty(activePkg.packagePath)) {
- try {
- return PackageParser.generatePackageInfoFromApex(
- new File(activePkg.packagePath), true /* collect certs */);
- } catch (PackageParserException pe) {
- Log.e(TAG, "Unable to parse package at "
- + activePkg.packagePath, pe);
- }
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to retrieve packages from apexservice: " + e.toString());
- }
- } else {
- Log.e(TAG, "Unable to connect to apexservice for querying packages.");
- }
+ return mApexManager.getActivePackage(packageName);
}
}
return null;
@@ -7851,25 +7844,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (listApex) {
// TODO(b/119767311): include uninstalled/inactive APEX if
// MATCH_UNINSTALLED_PACKAGES is set.
- final IApexService apex = IApexService.Stub.asInterface(
- ServiceManager.getService("apexservice"));
- if (apex != null) {
- try {
- final ApexInfo[] activePkgs = apex.getActivePackages();
- for (ApexInfo ai : activePkgs) {
- try {
- list.add(PackageParser.generatePackageInfoFromApex(
- new File(ai.packagePath), true /* collect certs */));
- } catch (PackageParserException pe) {
- throw new IllegalStateException("Unable to parse: " + ai, pe);
- }
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to retrieve packages from apexservice: " + e.toString());
- }
- } else {
- Log.e(TAG, "Unable to connect to apexservice for querying packages.");
- }
+ list.addAll(mApexManager.getActivePackages());
}
return new ParceledListSlice<>(list);
}
@@ -12836,7 +12811,7 @@ public class PackageManagerService extends IPackageManager.Stub
public String[] setDistractingPackageRestrictionsAsUser(String[] packageNames,
int restrictionFlags, int userId) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS,
- "setPackagesSuspendedAsUser");
+ "setDistractingPackageRestrictionsAsUser");
final int callingUid = Binder.getCallingUid();
if (callingUid != Process.ROOT_UID && callingUid != Process.SYSTEM_UID
@@ -14604,14 +14579,19 @@ public class PackageManagerService extends IPackageManager.Stub
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- // TODO(ruhler) b/112431924 Have a configurable setting to
- // allow changing the timeout and fall back to the default
- // if no such specified.
+ // the duration to wait for rollback to be enabled, in millis
+ long rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT;
+ try {
+ rollbackTimeout = Long.valueOf(
+ DeviceConfig.getProperty(
+ DeviceConfig.Rollback.NAMESPACE,
+ DeviceConfig.Rollback.ENABLE_ROLLBACK_TIMEOUT));
+ } catch (NumberFormatException ignore) {
+ }
final Message msg = mHandler.obtainMessage(
ENABLE_ROLLBACK_TIMEOUT);
msg.arg1 = enableRollbackToken;
- mHandler.sendMessageDelayed(msg,
- DEFAULT_ENABLE_ROLLBACK_TIMEOUT);
+ mHandler.sendMessageDelayed(msg, rollbackTimeout);
}
}, null, 0, null, null);
@@ -16321,7 +16301,6 @@ public class PackageManagerService extends IPackageManager.Stub
final boolean onExternal = args.volumeUuid != null;
final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0);
- final boolean forceSdk = ((installFlags & PackageManager.INSTALL_FORCE_SDK) != 0);
final boolean virtualPreload =
((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
@ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
@@ -16353,8 +16332,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Retrieve PackageSettings and parse package
@ParseFlags final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
| PackageParser.PARSE_ENFORCE_CODE
- | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0)
- | (forceSdk ? PackageParser.PARSE_FORCE_SDK : 0);
+ | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
@@ -16775,19 +16753,6 @@ public class PackageManagerService extends IPackageManager.Stub
"replacePackageLI: new=" + pkg + ", old=" + oldPackage);
}
- // don't allow upgrade to target a release SDK from a pre-release SDK
- final boolean oldTargetsPreRelease = oldPackage.applicationInfo.targetSdkVersion
- == Build.VERSION_CODES.CUR_DEVELOPMENT;
- final boolean newTargetsPreRelease = pkg.applicationInfo.targetSdkVersion
- == Build.VERSION_CODES.CUR_DEVELOPMENT;
- if (oldTargetsPreRelease
- && !newTargetsPreRelease
- && ((parseFlags & PackageParser.PARSE_FORCE_SDK) == 0)) {
- Slog.w(TAG, "Can't install package targeting released sdk");
- throw new PrepareFailure(
- PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE);
- }
-
ps = mSettings.mPackages.get(pkgName11);
disabledPs = mSettings.getDisabledSystemPkgLPr(ps);
@@ -19119,6 +19084,7 @@ public class PackageManagerService extends IPackageManager.Stub
pir.addFilter(new PreferredActivity(filter, match, set, activity, always));
scheduleWritePackageRestrictionsLocked(userId);
postPreferredActivityChangedBroadcast(userId);
+ updateDefaultHomeLPw(userId);
}
}
@@ -19269,6 +19235,13 @@ public class PackageManagerService extends IPackageManager.Stub
/** This method takes a specific user id as well as UserHandle.USER_ALL. */
@GuardedBy("mPackages")
boolean clearPackagePreferredActivitiesLPw(String packageName, int userId) {
+ return clearPackagePreferredActivitiesLPw(packageName, false, userId);
+ }
+
+ /** This method takes a specific user id as well as UserHandle.USER_ALL. */
+ @GuardedBy("mPackages")
+ private boolean clearPackagePreferredActivitiesLPw(String packageName,
+ boolean skipUpdateDefaultHome, int userId) {
ArrayList<PreferredActivity> removed = null;
boolean changed = false;
for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
@@ -19297,6 +19270,9 @@ public class PackageManagerService extends IPackageManager.Stub
pir.removeFilter(pa);
}
changed = true;
+ if (!skipUpdateDefaultHome) {
+ updateDefaultHomeLPw(thisUserId);
+ }
}
}
if (changed) {
@@ -19356,8 +19332,9 @@ public class PackageManagerService extends IPackageManager.Stub
// writer
try {
synchronized (mPackages) {
- clearPackagePreferredActivitiesLPw(null, userId);
+ clearPackagePreferredActivitiesLPw(null, true, userId);
mSettings.applyDefaultPreferredAppsLPw(userId);
+ updateDefaultHomeLPw(userId);
// TODO: We have to reset the default SMS and Phone. This requires
// significant refactoring to keep all default apps in the package
// manager (cleaner but more work) or have the services provide
@@ -19426,6 +19403,7 @@ public class PackageManagerService extends IPackageManager.Stub
new PersistentPreferredActivity(filter, activity));
scheduleWritePackageRestrictionsLocked(userId);
postPreferredActivityChangedBroadcast(userId);
+ updateDefaultHomeLPw(userId);
}
}
@@ -19469,6 +19447,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (changed) {
scheduleWritePackageRestrictionsLocked(userId);
postPreferredActivityChangedBroadcast(userId);
+ updateDefaultHomeLPw(userId);
}
}
}
@@ -19556,6 +19535,7 @@ public class PackageManagerService extends IPackageManager.Stub
(readParser, readUserId) -> {
synchronized (mPackages) {
mSettings.readPreferredActivitiesLPw(readParser, readUserId);
+ updateDefaultHomeLPw(readUserId);
}
});
} catch (Exception e) {
@@ -19611,8 +19591,17 @@ public class PackageManagerService extends IPackageManager.Stub
parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name());
restoreFromXml(parser, userId, TAG_DEFAULT_APPS,
(parser1, userId1) -> {
+ String defaultBrowser;
synchronized (mPackages) {
mSettings.readDefaultAppsLPw(parser1, userId1);
+ defaultBrowser = mSettings.removeDefaultBrowserPackageNameLPw(userId1);
+ }
+ if (defaultBrowser != null) {
+ PackageManagerInternal.DefaultBrowserProvider provider;
+ synchronized (mPackages) {
+ provider = mDefaultBrowserProvider;
+ }
+ provider.setDefaultBrowser(defaultBrowser, userId1);
}
});
} catch (Exception e) {
@@ -19970,19 +19959,59 @@ public class PackageManagerService extends IPackageManager.Stub
ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
int userId) {
Intent intent = getHomeIntent();
- List<ResolveInfo> list = queryIntentActivitiesInternal(intent, null,
+ List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null,
PackageManager.GET_META_DATA, userId);
- ResolveInfo preferred = findPreferredActivity(intent, null, 0, list, 0,
- true, false, false, userId);
-
allHomeCandidates.clear();
- if (list != null) {
- allHomeCandidates.addAll(list);
+ if (resolveInfos == null) {
+ return null;
}
- return (preferred == null || preferred.activityInfo == null)
- ? null
- : new ComponentName(preferred.activityInfo.packageName,
- preferred.activityInfo.name);
+ allHomeCandidates.addAll(resolveInfos);
+
+ PackageManagerInternal.DefaultHomeProvider provider;
+ synchronized (mPackages) {
+ provider = mDefaultHomeProvider;
+ }
+ if (provider == null) {
+ Slog.e(TAG, "mDefaultHomeProvider is null");
+ return null;
+ }
+ String packageName = provider.getDefaultHome(userId);
+ if (packageName == null) {
+ return null;
+ }
+ int resolveInfosSize = resolveInfos.size();
+ for (int i = 0; i < resolveInfosSize; i++) {
+ ResolveInfo resolveInfo = resolveInfos.get(i);
+
+ if (resolveInfo.activityInfo != null && TextUtils.equals(
+ resolveInfo.activityInfo.packageName, packageName)) {
+ return new ComponentName(resolveInfo.activityInfo.packageName,
+ resolveInfo.activityInfo.name);
+ }
+ }
+ return null;
+ }
+
+ private void updateDefaultHomeLPw(int userId) {
+ Intent intent = getHomeIntent();
+ List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null,
+ PackageManager.GET_META_DATA, userId);
+ ResolveInfo preferredResolveInfo = findPreferredActivity(intent, null, 0, resolveInfos,
+ 0, true, false, false, userId);
+ String packageName = preferredResolveInfo != null
+ && preferredResolveInfo.activityInfo != null
+ ? preferredResolveInfo.activityInfo.packageName : null;
+ String currentPackageName = mDefaultHomeProvider.getDefaultHome(userId);
+ if (TextUtils.equals(currentPackageName, packageName)) {
+ return;
+ }
+ String[] callingPackages = getPackagesForUid(Binder.getCallingUid());
+ if (callingPackages != null && ArrayUtils.contains(callingPackages,
+ mRequiredPermissionControllerPackage)) {
+ // PermissionController manages default home directly.
+ return;
+ }
+ mDefaultHomeProvider.setDefaultHomeAsync(packageName, userId);
}
@Override
@@ -21334,51 +21363,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_APEX)) {
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
- ipw.println();
- ipw.println("Active APEX packages:");
- ipw.increaseIndent();
- final IApexService apex = IApexService.Stub.asInterface(
- ServiceManager.getService("apexservice"));
- try {
- final ApexInfo[] activeApexes = apex.getActivePackages();
- for (ApexInfo ai : activeApexes) {
- if (packageName != null && !packageName.equals(ai.packageName)) {
- continue;
- }
- ipw.println(ai.packageName);
- ipw.increaseIndent();
- ipw.println("Version: " + Long.toString(ai.versionCode));
- ipw.println("Path: " + ai.packagePath);
- ipw.decreaseIndent();
- }
- ipw.decreaseIndent();
- ipw.println();
- ipw.println("APEX session state:");
- ipw.increaseIndent();
- final ApexSessionInfo[] sessions = apex.getSessions();
- for (ApexSessionInfo si : sessions) {
- ipw.println("Session ID: " + Integer.toString(si.sessionId));
- ipw.increaseIndent();
- if (si.isUnknown) {
- ipw.println("State: UNKNOWN");
- } else if (si.isVerified) {
- ipw.println("State: VERIFIED");
- } else if (si.isStaged) {
- ipw.println("State: STAGED");
- } else if (si.isActivated) {
- ipw.println("State: ACTIVATED");
- } else if (si.isActivationPendingRetry) {
- ipw.println("State: ACTIVATION PENDING RETRY");
- } else if (si.isActivationFailed) {
- ipw.println("State: ACTIVATION FAILED");
- }
- ipw.decreaseIndent();
- }
- ipw.decreaseIndent();
- } catch (RemoteException e) {
- ipw.println("Couldn't communicate with apexd.");
- }
+ mApexManager.dump(pw, packageName);
}
}
@@ -23916,6 +23901,13 @@ public class PackageManagerService extends IPackageManager.Stub
mDefaultBrowserProvider = provider;
}
}
+
+ @Override
+ public void setDefaultHomeProvider(@NonNull DefaultHomeProvider provider) {
+ synchronized (mPackages) {
+ mDefaultHomeProvider = provider;
+ }
+ }
}
@GuardedBy("mPackages")
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index dc18dfcf8613..2eb762b59be4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2383,8 +2383,7 @@ class PackageManagerShellCommand extends ShellCommand {
sessionParams.volumeUuid = null;
}
break;
- case "--force-sdk":
- sessionParams.installFlags |= PackageManager.INSTALL_FORCE_SDK;
+ case "--force-sdk": // ignore
break;
case "--apex":
sessionParams.setInstallAsApex();
@@ -2961,8 +2960,6 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" 0=unknown, 1=admin policy, 2=device restore,");
pw.println(" 3=device setup, 4=user request");
pw.println(" --force-uuid: force install on to disk volume with given UUID");
- pw.println(" --force-sdk: allow install even when existing app targets platform");
- pw.println(" codename but new one targets a final API level");
pw.println(" --apex: install an .apex file, not an .apk");
pw.println("");
pw.println(" install-create [-lrtsfdg] [-i PACKAGE] [--user USER_ID|all|current]");
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 84c8b606a9d9..d9a5eb901344 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -18,6 +18,7 @@ package com.android.server.pm;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.Person;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
@@ -33,6 +34,7 @@ import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.pm.ShortcutService.DumpFilter;
@@ -71,6 +73,7 @@ class ShortcutPackage extends ShortcutPackageItem {
private static final String TAG_EXTRAS = "extras";
private static final String TAG_SHORTCUT = "shortcut";
private static final String TAG_CATEGORIES = "categories";
+ private static final String TAG_PERSON = "person";
private static final String ATTR_NAME = "name";
private static final String ATTR_CALL_COUNT = "call-count";
@@ -96,6 +99,12 @@ class ShortcutPackage extends ShortcutPackageItem {
private static final String ATTR_ICON_RES_NAME = "icon-resname";
private static final String ATTR_BITMAP_PATH = "bitmap-path";
+ private static final String ATTR_PERSON_NAME = "name";
+ private static final String ATTR_PERSON_URI = "uri";
+ private static final String ATTR_PERSON_KEY = "key";
+ private static final String ATTR_PERSON_IS_BOT = "is-bot";
+ private static final String ATTR_PERSON_IS_IMPORTANT = "is-important";
+
private static final String NAME_CATEGORIES = "categories";
private static final String TAG_STRING_ARRAY_XMLUTILS = "string-array";
@@ -1499,6 +1508,22 @@ class ShortcutPackage extends ShortcutPackageItem {
out.endTag(null, TAG_CATEGORIES);
}
}
+ if (!forBackup) { // Don't backup the persons field.
+ final Person[] persons = si.getPersons();
+ if (!ArrayUtils.isEmpty(persons)) {
+ for (int i = 0; i < persons.length; i++) {
+ final Person p = persons[i];
+
+ out.startTag(null, TAG_PERSON);
+ ShortcutService.writeAttr(out, ATTR_PERSON_NAME, p.getName());
+ ShortcutService.writeAttr(out, ATTR_PERSON_URI, p.getUri());
+ ShortcutService.writeAttr(out, ATTR_PERSON_KEY, p.getKey());
+ ShortcutService.writeAttr(out, ATTR_PERSON_IS_BOT, p.isBot());
+ ShortcutService.writeAttr(out, ATTR_PERSON_IS_IMPORTANT, p.isImportant());
+ out.endTag(null, TAG_PERSON);
+ }
+ }
+ }
final Intent[] intentsNoExtras = si.getIntentsNoExtras();
final PersistableBundle[] intentsExtras = si.getIntentPersistableExtrases();
final int numIntents = intentsNoExtras.length;
@@ -1588,6 +1613,7 @@ class ShortcutPackage extends ShortcutPackageItem {
String bitmapPath;
int backupVersionCode;
ArraySet<String> categories = null;
+ ArrayList<Person> persons = new ArrayList<>();
id = ShortcutService.parseStringAttribute(parser, ATTR_ID);
activityComponent = ShortcutService.parseComponentNameAttribute(parser,
@@ -1638,6 +1664,9 @@ class ShortcutPackage extends ShortcutPackageItem {
case TAG_CATEGORIES:
// This just contains string-array.
continue;
+ case TAG_PERSON:
+ persons.add(parsePerson(parser));
+ continue;
case TAG_STRING_ARRAY_XMLUTILS:
if (NAME_CATEGORIES.equals(ShortcutService.parseStringAttribute(parser,
ATTR_NAME_XMLUTILS))) {
@@ -1680,7 +1709,8 @@ class ShortcutPackage extends ShortcutPackageItem {
categories,
intents.toArray(new Intent[intents.size()]),
rank, extras, lastChangedTimestamp, flags,
- iconResId, iconResName, bitmapPath, disabledReason);
+ iconResId, iconResName, bitmapPath, disabledReason,
+ persons.toArray(new Person[persons.size()]));
}
private static Intent parseIntent(XmlPullParser parser)
@@ -1713,6 +1743,20 @@ class ShortcutPackage extends ShortcutPackageItem {
return intent;
}
+ private static Person parsePerson(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ CharSequence name = ShortcutService.parseStringAttribute(parser, ATTR_PERSON_NAME);
+ String uri = ShortcutService.parseStringAttribute(parser, ATTR_PERSON_URI);
+ String key = ShortcutService.parseStringAttribute(parser, ATTR_PERSON_KEY);
+ boolean isBot = ShortcutService.parseBooleanAttribute(parser, ATTR_PERSON_IS_BOT);
+ boolean isImportant = ShortcutService.parseBooleanAttribute(parser,
+ ATTR_PERSON_IS_IMPORTANT);
+
+ Person.Builder builder = new Person.Builder();
+ builder.setName(name).setUri(uri).setKey(key).setBot(isBot).setImportant(isImportant);
+ return builder.build();
+ }
+
@VisibleForTesting
List<ShortcutInfo> getAllShortcutsForTest() {
return new ArrayList<>(mShortcuts.values());
diff --git a/services/core/java/com/android/server/pm/ShortcutParser.java b/services/core/java/com/android/server/pm/ShortcutParser.java
index 90f08c30139a..668fc88b6b58 100644
--- a/services/core/java/com/android/server/pm/ShortcutParser.java
+++ b/services/core/java/com/android/server/pm/ShortcutParser.java
@@ -449,7 +449,8 @@ public class ShortcutParser {
iconResId,
null, // icon res name
null, // bitmap path
- disabledReason);
+ disabledReason,
+ null /* persons */);
}
private static String parseCategory(ShortcutService service, AttributeSet attrs) {
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index fa8360b1e5ba..6c212d63d77c 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -20,12 +20,12 @@ import android.annotation.NonNull;
import android.apex.ApexInfo;
import android.apex.ApexInfoList;
import android.apex.ApexSessionInfo;
-import android.apex.IApexService;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageManager;
@@ -41,7 +41,6 @@ import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.text.TextUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.util.apk.ApkSignatureVerifier;
@@ -68,14 +67,16 @@ public class StagingManager {
private final PackageInstallerService mPi;
private final PackageManagerService mPm;
+ private final ApexManager mApexManager;
private final Handler mBgHandler;
@GuardedBy("mStagedSessions")
private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
- StagingManager(PackageManagerService pm, PackageInstallerService pi) {
+ StagingManager(PackageManagerService pm, PackageInstallerService pi, ApexManager am) {
mPm = pm;
mPi = pi;
+ mApexManager = am;
mBgHandler = BackgroundThread.getHandler();
}
@@ -100,7 +101,7 @@ public class StagingManager {
return new ParceledListSlice<>(result);
}
- private static boolean validateApexSignature(String apexPath, String packageName) {
+ private boolean validateApexSignature(String apexPath, String packageName) {
final SigningDetails signingDetails;
try {
signingDetails = ApkSignatureVerifier.verify(apexPath, SignatureSchemeVersion.JAR);
@@ -109,17 +110,9 @@ public class StagingManager {
return false;
}
- final IApexService apex = IApexService.Stub.asInterface(
- ServiceManager.getService("apexservice"));
- final ApexInfo apexInfo;
- try {
- apexInfo = apex.getActivePackage(packageName);
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to contact APEXD", re);
- return false;
- }
+ final PackageInfo packageInfo = mApexManager.getActivePackage(packageName);
- if (apexInfo == null || TextUtils.isEmpty(apexInfo.packageName)) {
+ if (packageInfo == null) {
// TODO: What is the right thing to do here ? This implies there's no active package
// with the given name. This should never be the case in production (where we only
// accept updates to existing APEXes) but may be required for testing.
@@ -129,9 +122,10 @@ public class StagingManager {
final SigningDetails existingSigningDetails;
try {
existingSigningDetails = ApkSignatureVerifier.verify(
- apexInfo.packagePath, SignatureSchemeVersion.JAR);
+ packageInfo.applicationInfo.sourceDir, SignatureSchemeVersion.JAR);
} catch (PackageParserException e) {
- Slog.e(TAG, "Unable to parse APEX package: " + apexInfo.packagePath, e);
+ Slog.e(TAG, "Unable to parse APEX package: "
+ + packageInfo.applicationInfo.sourceDir, e);
return false;
}
@@ -143,10 +137,10 @@ public class StagingManager {
return false;
}
- private static boolean submitSessionToApexService(@NonNull PackageInstallerSession session,
- List<PackageInstallerSession> childSessions,
- ApexInfoList apexInfoList) {
- return sendSubmitStagedSessionRequest(
+ private boolean submitSessionToApexService(@NonNull PackageInstallerSession session,
+ List<PackageInstallerSession> childSessions,
+ ApexInfoList apexInfoList) {
+ return mApexManager.submitStagedSession(
session.sessionId,
childSessions != null
? childSessions.stream().mapToInt(s -> s.sessionId).toArray() :
@@ -154,33 +148,6 @@ public class StagingManager {
apexInfoList);
}
- private static boolean sendSubmitStagedSessionRequest(
- int sessionId, int[] childSessionIds, ApexInfoList apexInfoList) {
- final IApexService apex = IApexService.Stub.asInterface(
- ServiceManager.getService("apexservice"));
- boolean success;
- try {
- success = apex.submitStagedSession(sessionId, childSessionIds, apexInfoList);
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to contact apexservice", re);
- return false;
- }
- return success;
- }
-
- private static boolean sendMarkStagedSessionReadyRequest(int sessionId) {
- final IApexService apex = IApexService.Stub.asInterface(
- ServiceManager.getService("apexservice"));
- boolean success;
- try {
- success = apex.markStagedSessionReady(sessionId);
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to contact apexservice", re);
- return false;
- }
- return success;
- }
-
private static boolean isApexSession(@NonNull PackageInstallerSession session) {
return (session.params.installFlags & PackageManager.INSTALL_APEX) != 0;
}
@@ -189,12 +156,8 @@ public class StagingManager {
boolean success = true;
// STOPSHIP: TODO(b/123753157): Verify APKs through Package Verifier.
- if (!sessionContainsApex(session)) {
- // TODO: Decide whether we want to fail fast by detecting signature mismatches for APKs,
- // right away.
- session.setStagedSessionReady();
- return;
- }
+ // TODO: Decide whether we want to fail fast by detecting signature mismatches for APKs,
+ // right away.
final ApexInfoList apexInfoList = new ApexInfoList();
// APEX checks. For single-package sessions, check if they contain an APEX. For
@@ -260,7 +223,8 @@ public class StagingManager {
}
session.setStagedSessionReady();
- if (!sendMarkStagedSessionReadyRequest(session.sessionId)) {
+ if (sessionContainsApex(session)
+ && !mApexManager.markStagedSessionReady(session.sessionId)) {
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
"APEX staging failed, check logcat messages from apexd for more "
+ "details.");
@@ -284,16 +248,12 @@ public class StagingManager {
private void resumeSession(@NonNull PackageInstallerSession session) {
if (sessionContainsApex(session)) {
- // Check with apexservice whether the apex
- // packages have been activated.
- final IApexService apex = IApexService.Stub.asInterface(
- ServiceManager.getService("apexservice"));
- ApexSessionInfo apexSessionInfo;
- try {
- apexSessionInfo = apex.getStagedSessionInfo(session.sessionId);
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to contact apexservice", re);
- // TODO should we retry here? Mark the session as failed?
+ // Check with apexservice whether the apex packages have been activated.
+ ApexSessionInfo apexSessionInfo = mApexManager.getStagedSessionInfo(session.sessionId);
+ if (apexSessionInfo == null) {
+ session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
+ "apexd did not know anything about a staged session supposed to be"
+ + "activated");
return;
}
if (apexSessionInfo.isActivationFailed || apexSessionInfo.isUnknown) {
@@ -323,8 +283,8 @@ public class StagingManager {
// The APEX part of the session is activated, proceed with the installation of APKs.
if (!installApksInSession(session)) {
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
- "APEX activation failed. Check logcat messages from apexd for "
- + "more information.");
+ "Staged installation of APKs failed. Check logcat messages for"
+ + "more information.");
return;
}
session.setStagedSessionApplied();
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 8d64b810b407..7e4365dafbe4 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -119,6 +119,7 @@ public class UserRestrictionsUtils {
UserManager.DISALLOW_OEM_UNLOCK,
UserManager.DISALLOW_UNMUTE_DEVICE,
UserManager.DISALLOW_AUTOFILL,
+ UserManager.DISALLOW_CONTENT_CAPTURE,
UserManager.DISALLOW_USER_SWITCH,
UserManager.DISALLOW_UNIFIED_PASSWORD,
UserManager.DISALLOW_CONFIG_LOCATION,
@@ -743,6 +744,9 @@ public class UserRestrictionsUtils {
case android.provider.Settings.Global.PRIVATE_DNS_MODE:
case android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER:
+ if (callingUid == Process.SYSTEM_UID) {
+ return false;
+ }
restriction = UserManager.DISALLOW_CONFIG_PRIVATE_DNS;
break;
default:
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 bfa539c9007e..bd577598a617 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -645,7 +645,7 @@ public final class DefaultPermissionGrantPolicy {
grantPermissionsToSystemPackage(packageName, userId,
CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS,
PHONE_PERMISSIONS, SMS_PERMISSIONS, CAMERA_PERMISSIONS,
- SENSORS_PERMISSIONS, STORAGE_PERMISSIONS);
+ SENSORS_PERMISSIONS, STORAGE_PERMISSIONS, MEDIA_AURAL_PERMISSIONS);
grantSystemFixedPermissionsToSystemPackage(packageName, userId,
LOCATION_PERMISSIONS, ACTIVITY_RECOGNITION_PERMISSIONS);
}
@@ -721,7 +721,7 @@ public final class DefaultPermissionGrantPolicy {
grantSystemFixedPermissionsToSystemPackage(
getDefaultSystemHandlerActivityPackage(
RingtoneManager.ACTION_RINGTONE_PICKER, userId),
- userId, STORAGE_PERMISSIONS);
+ userId, STORAGE_PERMISSIONS, MEDIA_AURAL_PERMISSIONS);
// TextClassifier Service
String textClassifierPackageName =
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b00193f5453f..2e3e3e430839 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -22,7 +22,6 @@ import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
import static android.app.AppOpsManager.OP_TOAST_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.content.Context.CONTEXT_RESTRICTED;
-import static android.content.Context.DISPLAY_SERVICE;
import static android.content.Context.WINDOW_SERVICE;
import static android.content.pm.PackageManager.FEATURE_HDMI_CEC;
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
@@ -36,6 +35,7 @@ import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.Display.STATE_OFF;
+import static android.view.KeyEvent.KEYCODE_UNKNOWN;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
@@ -84,10 +84,8 @@ import static android.view.WindowManagerGlobal.ADD_OKAY;
import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
-import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs
- .CAMERA_LENS_COVER_ABSENT;
-import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs
- .CAMERA_LENS_UNCOVERED;
+import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
+import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
import static com.android.server.wm.WindowManagerPolicyProto.KEYGUARD_DELEGATE;
@@ -371,6 +369,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
IStatusBarService mStatusBarService;
StatusBarManagerInternal mStatusBarManagerInternal;
AudioManagerInternal mAudioManagerInternal;
+ DisplayManager mDisplayManager;
boolean mPreloadedRecentApps;
final Object mServiceAquireLock = new Object();
Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
@@ -1717,7 +1716,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
- mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+ mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
+ mDisplayManager = mContext.getSystemService(DisplayManager.class);
mHasFeatureWatch = mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH);
mHasFeatureLeanback = mContext.getPackageManager().hasSystemFeature(FEATURE_LEANBACK);
mHasFeatureHdmiCec = mContext.getPackageManager().hasSystemFeature(FEATURE_HDMI_CEC);
@@ -2508,8 +2508,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return context;
}
- final DisplayManager dm = (DisplayManager) context.getSystemService(DISPLAY_SERVICE);
- final Display targetDisplay = dm.getDisplay(displayId);
+ final Display targetDisplay = mDisplayManager.getDisplay(displayId);
if (targetDisplay == null) {
// Failed to obtain the non-default display where splash screen should be shown,
// lets not show at all.
@@ -3655,7 +3654,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Reset the pending key
mPendingWakeKey = PENDING_KEY_NULL;
}
- } else if (!interactive && shouldDispatchInputWhenNonInteractive(event)) {
+ } else if (!interactive && shouldDispatchInputWhenNonInteractive(displayId, keyCode)) {
// If we're currently dozing with the screen on and the keyguard showing, pass the key
// to the application but preserve its wake key status to make sure we still move
// from dozing to fully interactive if we would normally go from off to fully
@@ -4126,7 +4125,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// TODO(b/117479243): handle it in InputPolicy
/** {@inheritDoc} */
@Override
- public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
+ public int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
+ int policyFlags) {
if ((policyFlags & FLAG_WAKE) != 0) {
if (wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotion,
PowerManager.WAKE_REASON_WAKE_MOTION, "android.policy:MOTION")) {
@@ -4134,7 +4134,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- if (shouldDispatchInputWhenNonInteractive(null)) {
+ if (shouldDispatchInputWhenNonInteractive(displayId, KEYCODE_UNKNOWN)) {
return ACTION_PASS_TO_USER;
}
@@ -4149,9 +4149,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return 0;
}
- private boolean shouldDispatchInputWhenNonInteractive(KeyEvent event) {
- final boolean displayOff = (mDefaultDisplay == null
- || mDefaultDisplay.getState() == STATE_OFF);
+ private boolean shouldDispatchInputWhenNonInteractive(int displayId, int keyCode) {
+ // Apply the default display policy to unknown displays as well.
+ final boolean isDefaultDisplay = displayId == DEFAULT_DISPLAY
+ || displayId == INVALID_DISPLAY;
+ final Display display = isDefaultDisplay
+ ? mDefaultDisplay
+ : mDisplayManager.getDisplay(displayId);
+ final boolean displayOff = (display == null
+ || display.getState() == STATE_OFF);
if (displayOff && !mHasFeatureWatch) {
return false;
@@ -4163,25 +4169,25 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
// Watches handle BACK specially
- if (mHasFeatureWatch
- && event != null
- && (event.getKeyCode() == KeyEvent.KEYCODE_BACK
- || event.getKeyCode() == KeyEvent.KEYCODE_STEM_PRIMARY)) {
+ if (mHasFeatureWatch && (keyCode == KeyEvent.KEYCODE_BACK
+ || keyCode == KeyEvent.KEYCODE_STEM_PRIMARY)) {
return false;
}
- // Send events to a dozing dream even if the screen is off since the dream
- // is in control of the state of the screen.
- IDreamManager dreamManager = getDreamManager();
+ // TODO(b/123372519): Refine when dream can support multi display.
+ if (isDefaultDisplay) {
+ // Send events to a dozing dream even if the screen is off since the dream
+ // is in control of the state of the screen.
+ IDreamManager dreamManager = getDreamManager();
- try {
- if (dreamManager != null && dreamManager.isDreaming()) {
- return true;
+ try {
+ if (dreamManager != null && dreamManager.isDreaming()) {
+ return true;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException when checking if dreaming", e);
}
- } catch (RemoteException e) {
- Slog.e(TAG, "RemoteException when checking if dreaming", e);
}
-
// Otherwise, consume events since the user can't see what is being
// interacted with.
return false;
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index d1bd102f11dc..870d61b2ab90 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -1003,11 +1003,13 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
* affect the power state of the device, for example, waking on motions.
* Generally, it's best to keep as little as possible in the queue thread
* because it's the most fragile.
+ * @param displayId The display ID of the motion event.
* @param policyFlags The policy flags associated with the motion.
*
* @return Actions flags: may be {@link #ACTION_PASS_TO_USER}.
*/
- public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);
+ int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
+ int policyFlags);
/**
* Called from the input dispatcher thread before a key is dispatched to a window.
diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
index 3534cf30e2bf..888dd9992bdf 100644
--- a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
+++ b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
@@ -17,10 +17,13 @@
package com.android.server.policy.role;
import android.annotation.NonNull;
+import android.annotation.UserIdInt;
import android.app.role.RoleManager;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.ResolveInfo;
import android.os.Debug;
import android.provider.Settings;
import android.telecom.TelecomManager;
@@ -33,6 +36,7 @@ import com.android.internal.util.CollectionUtils;
import com.android.server.LocalServices;
import com.android.server.role.RoleManagerService;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -54,19 +58,44 @@ public class LegacyRoleResolutionPolicy implements RoleManagerService.RoleHolder
@NonNull
private final Context mContext;
- public LegacyRoleResolutionPolicy(Context context) {
+ public LegacyRoleResolutionPolicy(@NonNull Context context) {
mContext = context;
}
+ @NonNull
@Override
- public List<String> getRoleHolders(String roleName, int userId) {
+ public List<String> getRoleHolders(@NonNull String roleName, @UserIdInt int userId) {
switch (roleName) {
+ case RoleManager.ROLE_ASSISTANT: {
+ String legacyAssistant = Settings.Secure.getStringForUser(
+ mContext.getContentResolver(), Settings.Secure.ASSISTANT, userId);
+ if (legacyAssistant == null || legacyAssistant.isEmpty()) {
+ return Collections.emptyList();
+ } else {
+ return Collections.singletonList(
+ ComponentName.unflattenFromString(legacyAssistant).getPackageName());
+ }
+ }
+ case RoleManager.ROLE_BROWSER: {
+ PackageManagerInternal packageManagerInternal = LocalServices.getService(
+ PackageManagerInternal.class);
+ String packageName = packageManagerInternal.removeLegacyDefaultBrowserPackageName(
+ userId);
+ return CollectionUtils.singletonOrEmpty(packageName);
+ }
+ case RoleManager.ROLE_DIALER: {
+ String setting = Settings.Secure.getStringForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.DIALER_DEFAULT_APPLICATION, userId);
+ return CollectionUtils.singletonOrEmpty(!TextUtils.isEmpty(setting)
+ ? setting
+ : mContext.getSystemService(TelecomManager.class).getSystemDialerPackage());
+ }
case RoleManager.ROLE_SMS: {
// Moved over from SmsApplication#getApplication
String result = Settings.Secure.getStringForUser(
mContext.getContentResolver(),
Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
-
// TODO: STOPSHIP: Remove the following code once we read the value of
// config_defaultSms in RoleControllerService.
if (result == null) {
@@ -92,34 +121,13 @@ public class LegacyRoleResolutionPolicy implements RoleManagerService.RoleHolder
SmsApplication.SmsApplicationData app = applicationData;
result = app == null ? null : app.mPackageName;
}
-
return CollectionUtils.singletonOrEmpty(result);
}
- case RoleManager.ROLE_ASSISTANT: {
- String legacyAssistant = Settings.Secure.getStringForUser(
- mContext.getContentResolver(), Settings.Secure.ASSISTANT, userId);
-
- if (legacyAssistant == null || legacyAssistant.isEmpty()) {
- return Collections.emptyList();
- } else {
- return Collections.singletonList(
- ComponentName.unflattenFromString(legacyAssistant).getPackageName());
- }
- }
- case RoleManager.ROLE_DIALER: {
- String setting = Settings.Secure.getStringForUser(
- mContext.getContentResolver(),
- Settings.Secure.DIALER_DEFAULT_APPLICATION, userId);
-
- return CollectionUtils.singletonOrEmpty(!TextUtils.isEmpty(setting)
- ? setting
- : mContext.getSystemService(TelecomManager.class).getSystemDialerPackage());
- }
- case RoleManager.ROLE_BROWSER: {
- PackageManagerInternal packageManagerInternal = LocalServices.getService(
- PackageManagerInternal.class);
- String packageName = packageManagerInternal.removeLegacyDefaultBrowserPackageName(
- userId);
+ case RoleManager.ROLE_HOME: {
+ PackageManager packageManager = mContext.getPackageManager();
+ List<ResolveInfo> resolveInfos = new ArrayList<>();
+ ComponentName componentName = packageManager.getHomeActivities(resolveInfos);
+ String packageName = componentName != null ? componentName.getPackageName() : null;
return CollectionUtils.singletonOrEmpty(packageName);
}
default: {
diff --git a/services/core/java/com/android/server/power/AttentionDetector.java b/services/core/java/com/android/server/power/AttentionDetector.java
index 4186154016e2..8740256af04d 100644
--- a/services/core/java/com/android/server/power/AttentionDetector.java
+++ b/services/core/java/com/android/server/power/AttentionDetector.java
@@ -123,6 +123,9 @@ public class AttentionDetector {
public AttentionDetector(Runnable onUserAttention, Object lock) {
mOnUserAttention = onUserAttention;
mLock = lock;
+
+ // Device starts with an awake state upon boot.
+ mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
}
public void systemReady(Context context) {
@@ -145,7 +148,7 @@ public class AttentionDetector {
if (DEBUG) {
Slog.d(TAG, "Do not check for attention yet, wait " + (whenToCheck - now));
}
- return nextScreenDimming;
+ return whenToCheck;
} else if (whenToStopExtending < whenToCheck) {
if (DEBUG) {
Slog.d(TAG, "Let device sleep to avoid false results and improve security "
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index 21bf9de5c8b0..d8531210cad8 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -111,7 +111,8 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
/** @see #getRoleHolders(String, int) */
public interface RoleHoldersResolver {
/** @return a list of packages that hold a given role for a given user */
- List<String> getRoleHolders(String roleName, int userId);
+ @NonNull
+ List<String> getRoleHolders(@NonNull String roleName, @UserIdInt int userId);
}
/**
@@ -154,6 +155,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
PackageManagerInternal packageManagerInternal = LocalServices.getService(
PackageManagerInternal.class);
packageManagerInternal.setDefaultBrowserProvider(new DefaultBrowserProvider());
+ packageManagerInternal.setDefaultHomeProvider(new DefaultHomeProvider());
registerUserRemovedReceiver();
}
@@ -741,4 +743,33 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
}
}
}
+
+ private class DefaultHomeProvider implements PackageManagerInternal.DefaultHomeProvider {
+
+ @Nullable
+ @Override
+ public String getDefaultHome(@UserIdInt int userId) {
+ return CollectionUtils.firstOrNull(getOrCreateUserState(userId).getRoleHolders(
+ RoleManager.ROLE_HOME));
+ }
+
+ @Override
+ public void setDefaultHomeAsync(@Nullable String packageName, @UserIdInt int userId) {
+ IRoleManagerCallback callback = new IRoleManagerCallback.Stub() {
+ @Override
+ public void onSuccess() {}
+ @Override
+ public void onFailure() {
+ Slog.e(LOG_TAG, "Failed to set default home: " + packageName);
+ }
+ };
+ if (packageName != null) {
+ getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_HOME,
+ packageName, 0, callback);
+ } else {
+ getOrCreateControllerService(userId).onClearRoleHolders(RoleManager.ROLE_HOME, 0,
+ callback);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 95c3f4c43313..ceaf829290d7 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -40,6 +40,7 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.provider.DeviceConfig;
import android.util.IntArray;
import android.util.Log;
import android.util.SparseBooleanArray;
@@ -61,6 +62,7 @@ import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
/**
* Implementation of service that manages APK level rollbacks.
@@ -71,13 +73,19 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
// Rollbacks expire after 48 hours.
// TODO: How to test rollback expiration works properly?
- private static final long ROLLBACK_LIFETIME_DURATION_MILLIS = 48 * 60 * 60 * 1000;
+ private static final long DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS =
+ TimeUnit.HOURS.toMillis(48);
// Lock used to synchronize accesses to in-memory rollback data
// structures. By convention, methods with the suffix "Locked" require
// mLock is held when they are called.
private final Object mLock = new Object();
+ // No need for guarding with lock because value is only accessed in handler thread
+ // and the value will be written on boot complete. Initialization here happens before
+ // handler threads are running so that's fine.
+ private long mRollbackLifetimeDurationInMillis = DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS;
+
// Used for generating rollback IDs.
private final Random mRandom = new SecureRandom();
@@ -484,7 +492,25 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
});
}
+ private void updateRollbackLifetimeDurationInMillis() {
+ String strRollbackLifetimeInMillis = DeviceConfig.getProperty(
+ DeviceConfig.Rollback.BOOT_NAMESPACE,
+ DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS);
+
+ try {
+ mRollbackLifetimeDurationInMillis = (strRollbackLifetimeInMillis == null)
+ ? DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS
+ : Long.parseLong(strRollbackLifetimeInMillis);
+ } catch (NumberFormatException e) {
+ mRollbackLifetimeDurationInMillis = DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS;
+ }
+ }
+
void onBootCompleted() {
+ getHandler().post(() -> updateRollbackLifetimeDurationInMillis());
+ // Also posts to handler thread
+ scheduleExpiration(0);
+
getHandler().post(() -> {
// Check to see if any staged sessions with rollback enabled have
// been applied.
@@ -565,8 +591,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
for (RollbackInfo info : mRecentlyExecutedRollbacks) {
mAllocatedRollbackIds.put(info.getRollbackId(), true);
}
-
- scheduleExpiration(0);
}
/**
@@ -700,8 +724,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
if (!data.isAvailable) {
continue;
}
-
- if (!now.isBefore(data.timestamp.plusMillis(ROLLBACK_LIFETIME_DURATION_MILLIS))) {
+ if (!now.isBefore(data.timestamp.plusMillis(mRollbackLifetimeDurationInMillis))) {
iter.remove();
deleteRollback(data);
} else if (oldest == null || oldest.isAfter(data.timestamp)) {
@@ -711,7 +734,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
}
if (oldest != null) {
- scheduleExpiration(now.until(oldest.plusMillis(ROLLBACK_LIFETIME_DURATION_MILLIS),
+ scheduleExpiration(now.until(oldest.plusMillis(mRollbackLifetimeDurationInMillis),
ChronoUnit.MILLIS));
}
}
@@ -1144,8 +1167,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
packages.add(data.packages.get(i).getPackageName());
}
mPackageHealthObserver.startObservingHealth(packages,
- ROLLBACK_LIFETIME_DURATION_MILLIS);
- scheduleExpiration(ROLLBACK_LIFETIME_DURATION_MILLIS);
+ mRollbackLifetimeDurationInMillis);
+ scheduleExpiration(mRollbackLifetimeDurationInMillis);
} catch (IOException e) {
Log.e(TAG, "Unable to enable rollback", e);
deleteRollback(data);
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 3c6a54af4bd7..3a2b69f8a6e1 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -16,8 +16,11 @@
package com.android.server.rollback;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.content.rollback.PackageRollbackInfo;
@@ -25,6 +28,7 @@ import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.PowerManager;
import android.text.TextUtils;
import android.util.Pair;
import android.util.Slog;
@@ -91,6 +95,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
+ failedPackage.getVersionCode() + "]");
return false;
}
+
RollbackInfo rollback = rollbackPair.first;
// We only log mainline package rollbacks, so check if rollback contains the
// module metadata provider, if it does, the rollback is a mainline rollback
@@ -111,6 +116,12 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
moduleMetadataPackage.getPackageName(),
moduleMetadataPackage.getVersionCode());
+ if (rollback.isStaged()) {
+ int rollbackId = rollback.getRollbackId();
+ BroadcastReceiver listener =
+ listenForStagedSessionReady(rollbackManager, rollbackId);
+ handleStagedSessionChange(rollbackManager, rollbackId, listener);
+ }
} else {
StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
@@ -178,4 +189,42 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
return null;
}
}
+
+ private BroadcastReceiver listenForStagedSessionReady(RollbackManager rollbackManager,
+ int rollbackId) {
+ BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ handleStagedSessionChange(rollbackManager,
+ rollbackId, this /* BroadcastReceiver */);
+ }
+ };
+ IntentFilter sessionUpdatedFilter =
+ new IntentFilter(PackageInstaller.ACTION_SESSION_UPDATED);
+ mContext.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter);
+ return sessionUpdatedReceiver;
+ }
+
+ private void handleStagedSessionChange(RollbackManager rollbackManager, int rollbackId,
+ BroadcastReceiver listener) {
+ PackageInstaller packageInstaller =
+ mContext.getPackageManager().getPackageInstaller();
+ List<RollbackInfo> recentRollbacks =
+ rollbackManager.getRecentlyCommittedRollbacks();
+ for (int i = 0; i < recentRollbacks.size(); i++) {
+ RollbackInfo recentRollback = recentRollbacks.get(i);
+ int sessionId = recentRollback.getCommittedSessionId();
+ if ((rollbackId == recentRollback.getRollbackId())
+ && (sessionId != PackageInstaller.SessionInfo.INVALID_ID)) {
+ PackageInstaller.SessionInfo sessionInfo =
+ packageInstaller.getSessionInfo(sessionId);
+ if (sessionInfo.isSessionReady()) {
+ mContext.unregisterReceiver(listener);
+ mContext.getSystemService(PowerManager.class).reboot("Rollback staged install");
+ } else if (sessionInfo.isSessionFailed()) {
+ mContext.unregisterReceiver(listener);
+ }
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index dd2cda20e0f1..f3393e2f29da 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -167,6 +167,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
public static final int CODE_DATA_BROADCAST = 1;
public static final int CODE_SUBSCRIBER_BROADCAST = 1;
+ public static final int CODE_ACTIVE_CONFIGS_BROADCAST = 1;
/**
* The last report time is provided with each intent registered to
* StatsManager#setFetchReportsOperation. This allows easy de-duping in the receiver if
@@ -356,6 +357,22 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
@Override
+ public void sendActiveConfigsChangedBroadcast(IBinder intentSenderBinder, long[] configIds) {
+ enforceCallingPermission();
+ IntentSender intentSender = new IntentSender(intentSenderBinder);
+ Intent intent = new Intent();
+ intent.putExtra(StatsManager.EXTRA_STATS_ACTIVE_CONFIG_KEYS, configIds);
+ try {
+ intentSender.sendIntent(mContext, CODE_ACTIVE_CONFIGS_BROADCAST, intent, null, null);
+ if (DEBUG) {
+ Slog.d(TAG, "Sent broadcast with config ids " + Arrays.toString(configIds));
+ }
+ } catch (IntentSender.SendIntentException e) {
+ Slog.w(TAG, "Unable to send active configs changed broadcast using IntentSender");
+ }
+ }
+
+ @Override
public void sendSubscriberBroadcast(IBinder intentSenderBinder, long configUid, long configKey,
long subscriptionId, long subscriptionRuleId, String[] cookies,
StatsDimensionsValue dimensionsValue) {
@@ -1169,7 +1186,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
BinderCallsStatsService.Internal binderStats =
LocalServices.getService(BinderCallsStatsService.Internal.class);
if (binderStats == null) {
- return;
+ throw new IllegalStateException("binderStats is null");
}
List<ExportedCallStat> callStats = binderStats.getExportedCallStats();
@@ -1200,7 +1217,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
BinderCallsStatsService.Internal binderStats =
LocalServices.getService(BinderCallsStatsService.Internal.class);
if (binderStats == null) {
- return;
+ throw new IllegalStateException("binderStats is null");
}
ArrayMap<String, Integer> exceptionStats = binderStats.getExportedExceptionStats();
@@ -1218,7 +1235,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
List<StatsLogEventWrapper> pulledData) {
LooperStats looperStats = LocalServices.getService(LooperStats.class);
if (looperStats == null) {
- return;
+ throw new IllegalStateException("looperStats null");
}
List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
@@ -1689,18 +1706,19 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
private void pullCpuTimePerThreadFreq(int tagId, long elapsedNanos, long wallClockNanos,
List<StatsLogEventWrapper> pulledData) {
if (this.mKernelCpuThreadReader == null) {
- return;
+ throw new IllegalStateException("mKernelCpuThreadReader is null");
}
ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsages =
this.mKernelCpuThreadReader.getProcessCpuUsageByUids();
if (processCpuUsages == null) {
- return;
+ throw new IllegalStateException("processCpuUsages is null");
}
int[] cpuFrequencies = mKernelCpuThreadReader.getCpuFrequenciesKhz();
if (cpuFrequencies.length > CPU_TIME_PER_THREAD_FREQ_MAX_NUM_FREQUENCIES) {
- Slog.w(TAG, "Expected maximum " + CPU_TIME_PER_THREAD_FREQ_MAX_NUM_FREQUENCIES
- + " frequencies, but got " + cpuFrequencies.length);
- return;
+ String message = "Expected maximum " + CPU_TIME_PER_THREAD_FREQ_MAX_NUM_FREQUENCIES
+ + " frequencies, but got " + cpuFrequencies.length;
+ Slog.w(TAG, message);
+ throw new IllegalStateException(message);
}
for (int i = 0; i < processCpuUsages.size(); i++) {
KernelCpuThreadReader.ProcessCpuUsage processCpuUsage = processCpuUsages.get(i);
@@ -1709,10 +1727,11 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
for (int j = 0; j < threadCpuUsages.size(); j++) {
KernelCpuThreadReader.ThreadCpuUsage threadCpuUsage = threadCpuUsages.get(j);
if (threadCpuUsage.usageTimesMillis.length != cpuFrequencies.length) {
- Slog.w(TAG, "Unexpected number of usage times,"
+ String message = "Unexpected number of usage times,"
+ " expected " + cpuFrequencies.length
- + " but got " + threadCpuUsage.usageTimesMillis.length);
- continue;
+ + " but got " + threadCpuUsage.usageTimesMillis.length;
+ Slog.w(TAG, message);
+ throw new IllegalStateException(message);
}
StatsLogEventWrapper e =
diff --git a/services/core/java/com/android/server/testharness/TestHarnessModeService.java b/services/core/java/com/android/server/testharness/TestHarnessModeService.java
index 4adce586e9a5..ec62ec76b32f 100644
--- a/services/core/java/com/android/server/testharness/TestHarnessModeService.java
+++ b/services/core/java/com/android/server/testharness/TestHarnessModeService.java
@@ -22,6 +22,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.UserInfo;
+import android.debug.AdbManagerInternal;
import android.os.BatteryManager;
import android.os.Binder;
import android.os.IBinder;
@@ -42,6 +43,7 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
+import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
@@ -49,7 +51,6 @@ import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
import java.util.Set;
@@ -85,6 +86,7 @@ public class TestHarnessModeService extends SystemService {
break;
case PHASE_BOOT_COMPLETED:
disableAutoSync();
+ configureSettings();
break;
}
super.onBootPhase(phase);
@@ -98,47 +100,60 @@ public class TestHarnessModeService extends SystemService {
return;
}
mShouldSetUpTestHarnessMode = true;
+ setUpAdb(testHarnessModeData);
+ setDeviceProvisioned();
+ }
+
+ private void setUpAdb(byte[] testHarnessModeData) {
+ ContentResolver cr = getContext().getContentResolver();
+ // Disable the TTL for ADB keys before enabling ADB
+ Settings.Global.putLong(cr, Settings.Global.ADB_ALLOWED_CONNECTION_TIME, 0);
+
PersistentData persistentData = PersistentData.fromBytes(testHarnessModeData);
SystemProperties.set(TEST_HARNESS_MODE_PROPERTY, persistentData.mEnabled ? "1" : "0");
writeAdbKeysFile(persistentData);
- // Clear out the data block so that we don't revert the ADB keys on every boot.
- getPersistentDataBlock().clearTestHarnessModeData();
+ }
- ContentResolver cr = getContext().getContentResolver();
- if (Settings.Global.getInt(cr, Settings.Global.ADB_ENABLED, 0) == 0) {
- // Enable ADB
- Settings.Global.putInt(cr, Settings.Global.ADB_ENABLED, 1);
- } else {
- // ADB is already enabled, we should restart the service so it picks up the new keys
- android.os.SystemService.restart("adbd");
+ private void disableAutoSync() {
+ if (!mShouldSetUpTestHarnessMode) {
+ return;
}
+ UserInfo primaryUser = UserManager.get(getContext()).getPrimaryUser();
+ ContentResolver
+ .setMasterSyncAutomaticallyAsUser(false, primaryUser.getUserHandle().getIdentifier());
+ }
+
+ private void configureSettings() {
+ if (!mShouldSetUpTestHarnessMode) {
+ return;
+ }
+ ContentResolver cr = getContext().getContentResolver();
+ Settings.Global.putInt(cr, Settings.Global.ADB_ENABLED, 1);
+ Settings.Global.putInt(cr, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
Settings.Global.putInt(cr, Settings.Global.PACKAGE_VERIFIER_ENABLE, 0);
Settings.Global.putInt(
cr,
Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
BatteryManager.BATTERY_PLUGGED_ANY);
Settings.Global.putInt(cr, Settings.Global.OTA_DISABLE_AUTOMATIC_UPDATE, 1);
- Settings.Global.putInt(cr, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
-
- setDeviceProvisioned();
}
- private void disableAutoSync() {
- if (!mShouldSetUpTestHarnessMode) {
- return;
- }
- UserInfo primaryUser = UserManager.get(getContext()).getPrimaryUser();
- ContentResolver
- .setMasterSyncAutomaticallyAsUser(false, primaryUser.getUserHandle().getIdentifier());
+ private void writeAdbKeysFile(PersistentData persistentData) {
+ AdbManagerInternal adbManager = LocalServices.getService(AdbManagerInternal.class);
+
+ writeBytesToFile(persistentData.mAdbKeys, adbManager.getAdbKeysFile().toPath());
+ writeBytesToFile(persistentData.mAdbTempKeys, adbManager.getAdbTempKeysFile().toPath());
+
+ // Clear out the data block so that we don't revert the ADB keys on every boot.
+ getPersistentDataBlock().clearTestHarnessModeData();
}
- private void writeAdbKeysFile(PersistentData persistentData) {
- Path adbKeys = Paths.get("/data/misc/adb/adb_keys");
+ private void writeBytesToFile(byte[] keys, Path adbKeys) {
try {
OutputStream fileOutputStream = Files.newOutputStream(adbKeys);
- fileOutputStream.write(persistentData.mAdbKeys);
+ fileOutputStream.write(keys);
fileOutputStream.close();
Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(adbKeys);
@@ -219,23 +234,22 @@ public class TestHarnessModeService extends SystemService {
}
private int handleEnable() {
- Path adbKeys = Paths.get("/data/misc/adb/adb_keys");
- if (!Files.exists(adbKeys)) {
+ AdbManagerInternal adbManager = LocalServices.getService(AdbManagerInternal.class);
+ File adbKeys = adbManager.getAdbKeysFile();
+ File adbTempKeys = adbManager.getAdbTempKeysFile();
+ if (adbKeys == null && adbTempKeys == null) {
// This should only be accessible on eng builds that haven't yet set up ADB keys
getErrPrintWriter()
.println("No ADB keys stored; not enabling test harness mode");
return 1;
}
- try (InputStream inputStream = Files.newInputStream(adbKeys)) {
- long size = Files.size(adbKeys);
- byte[] adbKeysBytes = new byte[(int) size];
- int numBytes = inputStream.read(adbKeysBytes);
- if (numBytes != size) {
- getErrPrintWriter().println("Failed to read all bytes of adb_keys");
- return 1;
- }
- PersistentData persistentData = new PersistentData(true, adbKeysBytes);
+ try {
+ byte[] adbKeysBytes = getBytesFromFile(adbKeys);
+ byte[] adbTempKeysBytes = getBytesFromFile(adbTempKeys);
+
+ PersistentData persistentData =
+ new PersistentData(true, adbKeysBytes, adbTempKeysBytes);
getPersistentDataBlock().setTestHarnessModeData(persistentData.toBytes());
} catch (IOException e) {
Slog.e(TAG, "Failed to store ADB keys.", e);
@@ -252,6 +266,22 @@ public class TestHarnessModeService extends SystemService {
return 0;
}
+ private byte[] getBytesFromFile(File file) throws IOException {
+ if (file == null || !file.exists()) {
+ return new byte[0];
+ }
+ Path path = file.toPath();
+ try (InputStream inputStream = Files.newInputStream(path)) {
+ int size = (int) Files.size(path);
+ byte[] bytes = new byte[size];
+ int numBytes = inputStream.read(bytes);
+ if (numBytes != size) {
+ throw new IOException("Failed to read the whole file");
+ }
+ return bytes;
+ }
+ }
+
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
@@ -290,15 +320,17 @@ public class TestHarnessModeService extends SystemService {
final int mVersion;
final boolean mEnabled;
final byte[] mAdbKeys;
+ final byte[] mAdbTempKeys;
- PersistentData(boolean enabled, byte[] adbKeys) {
- this(VERSION_1, enabled, adbKeys);
+ PersistentData(boolean enabled, byte[] adbKeys, byte[] adbTempKeys) {
+ this(VERSION_1, enabled, adbKeys, adbTempKeys);
}
- PersistentData(int version, boolean enabled, byte[] adbKeys) {
+ PersistentData(int version, boolean enabled, byte[] adbKeys, byte[] adbTempKeys) {
this.mVersion = version;
this.mEnabled = enabled;
this.mAdbKeys = adbKeys;
+ this.mAdbTempKeys = adbTempKeys;
}
static PersistentData fromBytes(byte[] bytes) {
@@ -309,7 +341,10 @@ public class TestHarnessModeService extends SystemService {
int adbKeysLength = is.readInt();
byte[] adbKeys = new byte[adbKeysLength];
is.readFully(adbKeys);
- return new PersistentData(version, enabled, adbKeys);
+ int adbTempKeysLength = is.readInt();
+ byte[] adbTempKeys = new byte[adbTempKeysLength];
+ is.readFully(adbTempKeys);
+ return new PersistentData(version, enabled, adbKeys, adbTempKeys);
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -323,6 +358,8 @@ public class TestHarnessModeService extends SystemService {
dos.writeBoolean(mEnabled);
dos.writeInt(mAdbKeys.length);
dos.write(mAdbKeys);
+ dos.writeInt(mAdbTempKeys.length);
+ dos.write(mAdbTempKeys);
dos.close();
return os.toByteArray();
} catch (IOException e) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 4faf910f52ea..f33c518941e5 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -75,12 +75,12 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
import static android.content.pm.ActivityInfo.isFixedOrientationPortrait;
import static android.content.res.Configuration.EMPTY;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET;
import static android.os.Build.VERSION_CODES.HONEYCOMB;
@@ -2610,10 +2610,6 @@ final class ActivityRecord extends ConfigurationContainer {
}
}
- int getRequestedOrientation() {
- return getOrientation();
- }
-
void setRequestedOrientation(int requestedOrientation) {
setOrientation(requestedOrientation, mayFreezeScreenLocked(app));
mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged(
@@ -2641,7 +2637,7 @@ final class ActivityRecord extends ConfigurationContainer {
int getOrientation() {
if (mAppWindowToken == null) {
- return SCREEN_ORIENTATION_UNSPECIFIED;
+ return info.screenOrientation;
}
return mAppWindowToken.getOrientationIgnoreVisibility();
@@ -2677,25 +2673,93 @@ final class ActivityRecord extends ConfigurationContainer {
mLastReportedConfiguration.setConfiguration(global, override);
}
+ /**
+ * Get the configuration orientation by the requested screen orientation
+ * ({@link ActivityInfo.ScreenOrientation}) of this activity.
+ *
+ * @return orientation in ({@link Configuration#ORIENTATION_LANDSCAPE},
+ * {@link Configuration#ORIENTATION_PORTRAIT},
+ * {@link Configuration#ORIENTATION_UNDEFINED}).
+ */
+ int getRequestedConfigurationOrientation() {
+ final int screenOrientation = getOrientation();
+ if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
+ // NOSENSOR means the display's "natural" orientation, so return that.
+ final ActivityDisplay display = getDisplay();
+ if (display != null && display.mDisplayContent != null) {
+ return display.mDisplayContent.getNaturalOrientation();
+ }
+ } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
+ // LOCKED means the activity's orientation remains unchanged, so return existing value.
+ return getConfiguration().orientation;
+ } else if (isFixedOrientationLandscape(screenOrientation)) {
+ return ORIENTATION_LANDSCAPE;
+ } else if (isFixedOrientationPortrait(screenOrientation)) {
+ return ORIENTATION_PORTRAIT;
+ }
+ return ORIENTATION_UNDEFINED;
+ }
+
+ /**
+ * Indicates the activity will keep the bounds and screen configuration when it was first
+ * launched, no matter how its parent changes.
+ *
+ * @return {@code true} if this activity is declared as non-resizable and fixed orientation or
+ * aspect ratio.
+ */
+ private boolean inSizeCompatMode() {
+ return !isResizeable() && (info.isFixedOrientation() || info.hasFixedAspectRatio())
+ // The configuration of non-standard type should be enforced by system.
+ && isActivityTypeStandard()
+ && !mAtmService.mForceResizableActivities;
+ }
+
// TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
private void updateOverrideConfiguration() {
+ final boolean inSizeCompatMode = inSizeCompatMode();
+ if (inSizeCompatMode) {
+ if (!matchParentBounds()) {
+ // The override configuration is set only once in size compatible mode.
+ return;
+ }
+ if (!hasProcess() && !isConfigurationCompatible(task.getConfiguration())) {
+ // Don't compute when launching in fullscreen and the fixed orientation is not the
+ // current orientation. It is more accurately to compute the override bounds from
+ // the updated configuration after the fixed orientation is applied.
+ return;
+ }
+ }
+
computeBounds(mTmpBounds);
+ if (inSizeCompatMode && mTmpBounds.isEmpty()) {
+ mTmpBounds.set(task.getWindowConfiguration().getBounds());
+ }
if (mTmpBounds.equals(getRequestedOverrideBounds())) {
+ // The bounds is not changed or the activity is resizable (both the 2 bounds are empty).
return;
}
- setBounds(mTmpBounds);
-
- // Bounds changed...update configuration to match.
- if (!matchParentBounds()) {
- mTmpConfig.setTo(getRequestedOverrideConfiguration());
- task.computeConfigResourceOverrides(mTmpConfig, task.getParent().getConfiguration());
- } else {
- mTmpConfig.unset();
+ final Configuration overrideConfig = mTmpConfig;
+ overrideConfig.unset();
+ if (!mTmpBounds.isEmpty()) {
+ overrideConfig.windowConfiguration.setBounds(mTmpBounds);
+ if (inSizeCompatMode) {
+ // Ensure the screen related fields are set. It is used to prevent activity relaunch
+ // when moving between displays. For screenWidthDp and screenWidthDp, because they
+ // are relative to bounds and density, they will be calculated in
+ // {@link TaskRecord#computeConfigResourceOverrides} and the result will also be
+ // relatively fixed.
+ final Configuration srcConfig = task.getConfiguration();
+ overrideConfig.colorMode = srcConfig.colorMode;
+ overrideConfig.densityDpi = srcConfig.densityDpi;
+ overrideConfig.screenLayout = srcConfig.screenLayout;
+ // The smallest screen width is the short side of screen bounds. Because the bounds
+ // and density won't be changed, smallestScreenWidthDp is also fixed.
+ overrideConfig.smallestScreenWidthDp = srcConfig.smallestScreenWidthDp;
+ }
}
-
- onRequestedOverrideConfigurationChanged(mTmpConfig);
+ onRequestedOverrideConfigurationChanged(overrideConfig);
}
@Override
@@ -2707,6 +2771,86 @@ final class ActivityRecord extends ConfigurationContainer {
// layout traversals.
mConfigurationSeq = Math.max(++mConfigurationSeq, 1);
getResolvedOverrideConfiguration().seq = mConfigurationSeq;
+
+ if (matchParentBounds()) {
+ return;
+ }
+
+ final Configuration resolvedConfig = getResolvedOverrideConfiguration();
+ if (!inSizeCompatMode()) {
+ computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
+ ORIENTATION_UNDEFINED, true /* insideParentBounds */);
+ return;
+ }
+
+ final Configuration displayConfig = getDisplay().getConfiguration();
+ int orientation = getConfiguration().orientation;
+ if (orientation != displayConfig.orientation && isConfigurationCompatible(displayConfig)) {
+ // The activity is compatible to apply the orientation change or it requests different
+ // fixed orientation.
+ orientation = displayConfig.orientation;
+ } else {
+ if (resolvedConfig.windowConfiguration.getAppBounds() != null) {
+ // Keep the computed resolved override configuration.
+ return;
+ }
+ final int requestedOrientation = getRequestedConfigurationOrientation();
+ if (requestedOrientation != ORIENTATION_UNDEFINED) {
+ orientation = requestedOrientation;
+ }
+ }
+
+ // Adjust the bounds to match the current orientation.
+ if (orientation != ORIENTATION_UNDEFINED) {
+ final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
+ final int longSide = Math.max(resolvedBounds.height(), resolvedBounds.width());
+ final int shortSide = Math.min(resolvedBounds.height(), resolvedBounds.width());
+ final boolean toBeLandscape = orientation == ORIENTATION_LANDSCAPE;
+ final int width = toBeLandscape ? longSide : shortSide;
+ final int height = toBeLandscape ? shortSide : longSide;
+ // Assume the bounds is always started from zero because the size may be bigger than its
+ // parent (task ~ display). The actual letterboxing will be done by surface offset.
+ resolvedBounds.set(0, 0, width, height);
+ }
+
+ // In size compatible mode, activity is allowed to have larger bounds than its parent.
+ computeConfigResourceOverrides(resolvedConfig, newParentConfiguration, orientation,
+ false /* insideParentBounds */);
+ }
+
+ private void computeConfigResourceOverrides(Configuration inOutConfig,
+ Configuration parentConfig, int orientation, boolean insideParentBounds) {
+ // Set the real orientation or undefined value to ensure the output orientation won't be the
+ // old value. Also reset app bounds so it will be updated according to bounds.
+ inOutConfig.orientation = orientation;
+ final Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
+ if (outAppBounds != null) {
+ outAppBounds.setEmpty();
+ }
+
+ // TODO(b/112288258): Remove below calculation because the position information in bounds
+ // will be replaced by the offset of surface.
+ final Rect appBounds = parentConfig.windowConfiguration.getAppBounds();
+ if (appBounds != null) {
+ final Rect outBounds = inOutConfig.windowConfiguration.getBounds();
+ final int activityWidth = outBounds.width();
+ final int navBarPosition = mAtmService.mWindowManager.getNavBarPosition(getDisplayId());
+ if (navBarPosition == NAV_BAR_LEFT) {
+ // Position the activity frame on the opposite side of the nav bar.
+ outBounds.left = appBounds.right - activityWidth;
+ outBounds.right = appBounds.right;
+ } else if (navBarPosition == NAV_BAR_RIGHT) {
+ // Position the activity frame on the opposite side of the nav bar.
+ outBounds.left = 0;
+ outBounds.right = activityWidth + appBounds.left;
+ } else if (appBounds.width() > activityWidth) {
+ // Horizontally center the frame.
+ outBounds.left = appBounds.left + (appBounds.width() - activityWidth) / 2;
+ outBounds.right = outBounds.left + activityWidth;
+ }
+ }
+
+ task.computeConfigResourceOverrides(inOutConfig, parentConfig, insideParentBounds);
}
@Override
@@ -2739,8 +2883,7 @@ final class ActivityRecord extends ConfigurationContainer {
/** Returns true if the configuration is compatible with this activity. */
boolean isConfigurationCompatible(Configuration config) {
- final int orientation = mAppWindowToken != null
- ? getOrientation() : info.screenOrientation;
+ final int orientation = getOrientation();
if (isFixedOrientationPortrait(orientation)
&& config.orientation != ORIENTATION_PORTRAIT) {
return false;
@@ -2794,14 +2937,36 @@ final class ActivityRecord extends ConfigurationContainer {
// should be given the aspect ratio.
activityWidth = (int) ((activityHeight * maxAspectRatio) + 0.5f);
}
- } else if (containingRatio < minAspectRatio && minAspectRatio != 0) {
- if (containingAppWidth < containingAppHeight) {
- // Width is the shorter side, so we use the height to figure-out what the max. width
- // should be given the aspect ratio.
+ } else if (containingRatio < minAspectRatio) {
+ boolean adjustWidth;
+ switch (getRequestedConfigurationOrientation()) {
+ case ORIENTATION_LANDSCAPE:
+ // Width should be the longer side for this landscape app, so we use the width
+ // to figure-out what the max. height should be given the aspect ratio.
+ adjustWidth = false;
+ break;
+ case ORIENTATION_PORTRAIT:
+ // Height should be the longer side for this portrait app, so we use the height
+ // to figure-out what the max. width should be given the aspect ratio.
+ adjustWidth = true;
+ break;
+ default:
+ // This app doesn't have a preferred orientation, so we keep the length of the
+ // longer side, and use it to figure-out the length of the shorter side.
+ if (containingAppWidth < containingAppHeight) {
+ // Width is the shorter side, so we use the height to figure-out what the
+ // max. width should be given the aspect ratio.
+ adjustWidth = true;
+ } else {
+ // Height is the shorter side, so we use the width to figure-out what the
+ // max. height should be given the aspect ratio.
+ adjustWidth = false;
+ }
+ break;
+ }
+ if (adjustWidth) {
activityWidth = (int) ((activityHeight / minAspectRatio) + 0.5f);
} else {
- // Height is the shorter side, so we use the width to figure-out what the max.
- // height should be given the aspect ratio.
activityHeight = (int) ((activityWidth / minAspectRatio) + 0.5f);
}
}
@@ -2822,21 +2987,6 @@ final class ActivityRecord extends ConfigurationContainer {
// away later in StackWindowController.adjustConfigurationForBounds(). Otherwise, the app
// bounds would end up too small.
outBounds.set(0, 0, activityWidth + appBounds.left, activityHeight + appBounds.top);
-
- final int navBarPosition = mAtmService.mWindowManager.getNavBarPosition(getDisplayId());
- if (navBarPosition == NAV_BAR_LEFT) {
- // Position the activity frame on the opposite side of the nav bar.
- outBounds.left = appBounds.right - activityWidth;
- outBounds.right = appBounds.right;
- } else if (navBarPosition == NAV_BAR_RIGHT) {
- // Position the activity frame on the opposite side of the nav bar.
- outBounds.left = 0;
- outBounds.right = activityWidth + appBounds.left;
- } else {
- // Horizontally center the frame.
- outBounds.left = appBounds.left + (containingAppWidth - activityWidth) / 2;
- outBounds.right = outBounds.left + activityWidth;
- }
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index cc78588eeb84..932cfd3ae007 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -5631,6 +5631,19 @@ class ActivityStack extends ConfigurationContainer {
}
}
+ /**
+ * Get current bounds of this stack, return empty when it is unavailable.
+ * @see TaskStack#getAnimationOrCurrentBounds(Rect)
+ */
+ void getAnimationOrCurrentBounds(Rect outBounds) {
+ final TaskStack stack = getTaskStack();
+ if (stack == null) {
+ outBounds.setEmpty();
+ return;
+ }
+ stack.getAnimationOrCurrentBounds(outBounds);
+ }
+
private boolean skipResizeAnimation(boolean toFullscreen) {
if (!toFullscreen) {
return false;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 678a896bddbc..c33a2c179ab7 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -989,8 +989,8 @@ class ActivityStarter {
if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
return false;
}
- // don't abort if the callingPackage is a device owner
- if (mService.getDevicePolicyManager().isDeviceOwnerApp(callingPackage)) {
+ // don't abort if the callingPackage is the device owner
+ if (mService.isDeviceOwner(callingPackage)) {
return false;
}
// anything that has fallen through would currently be aborted
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 1a5e6a14e733..5a20959dcdbf 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -492,4 +492,9 @@ public abstract class ActivityTaskManagerInternal {
/** Returns true if uid has a visible window or its process is in a top state. */
public abstract boolean isUidForeground(int uid);
+
+ /**
+ * Called by DevicePolicyManagerService to set the package name of the device owner.
+ */
+ public abstract void setDeviceOwnerPackageName(String deviceOwnerPkg);
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 875fc4eab273..258819fdece9 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -151,7 +151,6 @@ import android.app.RemoteAction;
import android.app.WaitResult;
import android.app.WindowConfiguration;
import android.app.admin.DevicePolicyCache;
-import android.app.admin.DevicePolicyManager;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.usage.UsageStatsManagerInternal;
@@ -363,7 +362,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
WindowManagerService mWindowManager;
private UserManagerService mUserManager;
private AppOpsService mAppOpsService;
- private DevicePolicyManager mDpm;
/** All active uids in the system. */
private final SparseArray<Integer> mActiveUids = new SparseArray<>();
private final SparseArray<String> mPendingTempWhitelist = new SparseArray<>();
@@ -623,6 +621,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
private FontScaleSettingObserver mFontScaleSettingObserver;
+ private String mDeviceOwnerPackageName;
+
private final class FontScaleSettingObserver extends ContentObserver {
private final Uri mFontScaleUri = Settings.System.getUriFor(FONT_SCALE);
private final Uri mHideErrorDialogsUri = Settings.Global.getUriFor(HIDE_ERROR_DIALOGS);
@@ -838,13 +838,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return mAppOpsService;
}
- DevicePolicyManager getDevicePolicyManager() {
- if (mDpm == null) {
- mDpm = mContext.getSystemService(DevicePolicyManager.class);
- }
- return mDpm;
- }
-
boolean hasUserRestriction(String restriction, int userId) {
return getUserManager().hasUserRestriction(restriction, userId);
}
@@ -1720,7 +1713,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (r == null) {
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
- return r.getRequestedOrientation();
+ return r.getOrientation();
}
}
@@ -2452,6 +2445,40 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
+ @Override
+ public void offsetPinnedStackBounds(int stackId, Rect compareBounds, int xOffset, int yOffset,
+ int animationDuration) {
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "offsetPinnedStackBounds()");
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ if (xOffset == 0 && yOffset == 0) {
+ return;
+ }
+ final ActivityStack stack = mRootActivityContainer.getStack(stackId);
+ if (stack == null) {
+ Slog.w(TAG, "offsetPinnedStackBounds: stackId " + stackId + " not found.");
+ return;
+ }
+ if (stack.getWindowingMode() != WINDOWING_MODE_PINNED) {
+ throw new IllegalArgumentException("Stack: " + stackId
+ + " doesn't support animated resize.");
+ }
+ final Rect destBounds = new Rect();
+ stack.getAnimationOrCurrentBounds(destBounds);
+ if (!destBounds.isEmpty() || !destBounds.equals(compareBounds)) {
+ Slog.w(TAG, "The current stack bounds does not matched! It may be obsolete.");
+ return;
+ }
+ destBounds.offset(xOffset, yOffset);
+ stack.animateResizePinnedStack(null /* sourceHintBounds */, destBounds,
+ animationDuration, false /* fromFullscreen */);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
/**
* Moves the specified task to the primary-split-screen stack.
*
@@ -5691,6 +5718,17 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|| mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid);
}
+ boolean isDeviceOwner(String packageName) {
+ if (packageName == null) {
+ return false;
+ }
+ return packageName.equals(mDeviceOwnerPackageName);
+ }
+
+ void setDeviceOwnerPackageName(String deviceOwnerPkg) {
+ mDeviceOwnerPackageName = deviceOwnerPkg;
+ }
+
/**
* @return whitelist tag for a uid from mPendingTempWhitelist, null if not currently on
* the whitelist
@@ -7108,5 +7146,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return ActivityTaskManagerService.this.isUidForeground(uid);
}
}
+
+ @Override
+ public void setDeviceOwnerPackageName(String deviceOwnerPkg) {
+ synchronized (mGlobalLock) {
+ ActivityTaskManagerService.this.setDeviceOwnerPackageName(deviceOwnerPkg);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
index 0e14e46e77de..5519729c17f5 100644
--- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java
+++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
@@ -143,7 +143,7 @@ class AppWindowThumbnail implements Animatable {
void destroy() {
mSurfaceAnimator.cancelAnimation();
- mSurfaceControl.remove();
+ getPendingTransaction().remove(mSurfaceControl);
}
/**
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 2cc85e2076e0..88c8b953a2e9 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -239,6 +239,17 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
+ /**
+ * The scale to fit at least one side of the activity to its parent. If the activity uses
+ * 1920x1080, and the actually size on the screen is 960x540, then the scale is 0.5.
+ */
+ private float mSizeCompatScale = 1f;
+ /**
+ * The bounds in global coordinates for activity in size compatibility mode.
+ * @see ActivityRecord#inSizeCompatMode
+ */
+ private Rect mSizeCompatBounds;
+
private boolean mDisablePreviewScreenshots;
private Task mLastParent;
@@ -884,6 +895,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
dc.setFocusedApp(null);
mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
}
+ if (mLetterbox != null) {
+ mLetterbox.destroy();
+ mLetterbox = null;
+ }
if (!delayed) {
updateReportedVisibilityLocked();
@@ -1275,7 +1290,19 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
void onDisplayChanged(DisplayContent dc) {
DisplayContent prevDc = mDisplayContent;
super.onDisplayChanged(dc);
- if (prevDc != null && prevDc.mFocusedApp == this) {
+ if (prevDc == null) {
+ return;
+ }
+ if (prevDc.mChangingApps.contains(this)) {
+ // This gets called *after* the AppWindowToken has been reparented to the new display.
+ // That reparenting resulted in this window changing modes (eg. FREEFORM -> FULLSCREEN),
+ // so this token is now "frozen" while waiting for the animation to start on prevDc
+ // (which will be cancelled since the window is no-longer a child). However, since this
+ // is no longer a child of prevDc, this won't be notified of the cancelled animation,
+ // so we need to cancel the change transition here.
+ clearChangeLeash(getPendingTransaction(), true /* cancel */);
+ }
+ if (prevDc.mFocusedApp == this) {
prevDc.setFocusedApp(null);
final TaskStack stack = dc.getTopStack();
if (stack != null) {
@@ -1285,6 +1312,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
}
}
}
+
+ if (prevDc != mDisplayContent && mLetterbox != null) {
+ mLetterbox.onMovedToDisplay(mDisplayContent.getDisplayId());
+ }
}
/**
@@ -1543,11 +1574,52 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
return mOrientation;
}
+ /** @return {@code true} if the compatibility bounds is taking effect. */
+ boolean inSizeCompatMode() {
+ return mSizeCompatBounds != null;
+ }
+
+ @Override
+ float getSizeCompatScale() {
+ return inSizeCompatMode() ? mSizeCompatScale : super.getSizeCompatScale();
+ }
+
+ /**
+ * @return Non-empty bounds if the activity has override bounds.
+ * @see ActivityRecord#resolveOverrideConfiguration(Configuration)
+ */
+ Rect getResolvedOverrideBounds() {
+ // Get bounds from resolved override configuration because it is computed with orientation.
+ return getResolvedOverrideConfiguration().windowConfiguration.getBounds();
+ }
+
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
final int prevWinMode = getWindowingMode();
mTmpPrevBounds.set(getBounds());
super.onConfigurationChanged(newParentConfig);
+
+ final Task task = getTask();
+ final Rect overrideBounds = getResolvedOverrideBounds();
+ if (task != null && !overrideBounds.isEmpty()
+ // If the changes come from change-listener, the incoming parent configuration is
+ // still the old one. Make sure their orientations are the same to reduce computing
+ // the compatibility bounds for the intermediate state.
+ && getResolvedOverrideConfiguration().orientation == newParentConfig.orientation) {
+ final Rect taskBounds = task.getBounds();
+ // Since we only center the activity horizontally, if only the fixed height is smaller
+ // than its container, the override bounds don't need to take effect.
+ if ((overrideBounds.width() != taskBounds.width()
+ || overrideBounds.height() > taskBounds.height())) {
+ calculateCompatBoundsTransformation(newParentConfig);
+ updateSurfacePosition();
+ } else if (mSizeCompatBounds != null) {
+ mSizeCompatBounds = null;
+ mSizeCompatScale = 1f;
+ updateSurfacePosition();
+ }
+ }
+
final int winMode = getWindowingMode();
if (prevWinMode == winMode) {
@@ -1584,7 +1656,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
}
private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) {
- if (!isVisible() || getDisplayContent().mAppTransition.isTransitionSet()) {
+ if (mWmService.mDisableTransitionAnimation
+ || !isVisible()
+ || getDisplayContent().mAppTransition.isTransitionSet()
+ || getSurfaceControl() == null) {
return false;
}
// Only do an animation into and out-of freeform mode for now. Other mode
@@ -1642,8 +1717,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
final ActivityManager.TaskSnapshot snapshot = snapshotCtrl.getSnapshot(
getTask().mTaskId, getTask().mUserId, false /* restoreFromDisk */,
false /* reducedResolution */);
- mThumbnail = new AppWindowThumbnail(t, this, snapshot.getSnapshot(),
- true /* relative */);
+ if (snapshot != null) {
+ mThumbnail = new AppWindowThumbnail(t, this, snapshot.getSnapshot(),
+ true /* relative */);
+ }
}
}
@@ -1656,6 +1733,54 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
return mThumbnail;
}
+ /**
+ * Calculates the scale and offset to horizontal center the size compatibility bounds into the
+ * region which is available to application.
+ */
+ private void calculateCompatBoundsTransformation(Configuration newParentConfig) {
+ final Rect parentAppBounds = newParentConfig.windowConfiguration.getAppBounds();
+ final Rect viewportBounds = parentAppBounds != null
+ ? parentAppBounds : newParentConfig.windowConfiguration.getBounds();
+ final Rect contentBounds = getResolvedOverrideBounds();
+ final float contentW = contentBounds.width();
+ final float contentH = contentBounds.height();
+ final float viewportW = viewportBounds.width();
+ final float viewportH = viewportBounds.height();
+ // Only allow to scale down.
+ mSizeCompatScale = (contentW <= viewportW && contentH <= viewportH)
+ ? 1 : Math.min(viewportW / contentW, viewportH / contentH);
+ final int offsetX = (int) ((viewportW - contentW * mSizeCompatScale + 1) * 0.5f)
+ + viewportBounds.left;
+
+ if (mSizeCompatBounds == null) {
+ mSizeCompatBounds = new Rect();
+ }
+ mSizeCompatBounds.set(contentBounds);
+ mSizeCompatBounds.offsetTo(0, 0);
+ mSizeCompatBounds.scale(mSizeCompatScale);
+ mSizeCompatBounds.left += offsetX;
+ mSizeCompatBounds.right += offsetX;
+ }
+
+ @Override
+ public Rect getBounds() {
+ if (mSizeCompatBounds != null) {
+ return mSizeCompatBounds;
+ }
+ return super.getBounds();
+ }
+
+ @Override
+ public boolean matchParentBounds() {
+ if (super.matchParentBounds()) {
+ return true;
+ }
+ // An activity in size compatibility mode may have override bounds which equals to its
+ // parent bounds, so the exact bounds should also be checked.
+ final WindowContainer parent = getParent();
+ return parent == null || parent.getBounds().equals(getResolvedOverrideBounds());
+ }
+
@Override
void checkAppWindowsReadyToShow() {
if (allDrawn == mLastAllDrawn) {
@@ -1829,6 +1954,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
if (needsLetterbox) {
if (mLetterbox == null) {
mLetterbox = new Letterbox(() -> makeChildSurface(null));
+ mLetterbox.attachInput(w);
}
getPosition(mTmpPoint);
mLetterbox.layout(getParent().getBounds(), w.getFrameLw(), mTmpPoint);
@@ -2561,9 +2687,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
return;
} else if (mTransitChangeLeash != null) {
// unparent mTransitChangeLeash for clean-up
- t.hide(mTransitChangeLeash);
- t.reparent(mTransitChangeLeash, null);
- mTransitChangeLeash = null;
+ clearChangeLeash(t, false /* cancel */);
}
if (mAnimatingAppWindowTokenRegistry != null) {
@@ -2659,15 +2783,36 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
return super.isSelfAnimating();
}
+ /**
+ * @param cancel {@code true} if clearing the leash due to cancelling instead of transferring
+ * to another leash.
+ */
+ private void clearChangeLeash(Transaction t, boolean cancel) {
+ if (mTransitChangeLeash == null) {
+ return;
+ }
+ if (cancel) {
+ clearThumbnail();
+ SurfaceControl sc = getSurfaceControl();
+ SurfaceControl parentSc = getParentSurfaceControl();
+ // Don't reparent if surface is getting destroyed
+ if (parentSc != null && sc != null) {
+ t.reparent(sc, getParentSurfaceControl());
+ }
+ }
+ t.hide(mTransitChangeLeash);
+ t.reparent(mTransitChangeLeash, null);
+ mTransitChangeLeash = null;
+ if (cancel) {
+ onAnimationLeashDestroyed(t);
+ }
+ }
+
@Override
void cancelAnimation() {
cancelAnimationOnly();
clearThumbnail();
- if (mTransitChangeLeash != null) {
- getPendingTransaction().hide(mTransitChangeLeash);
- getPendingTransaction().reparent(mTransitChangeLeash, null);
- mTransitChangeLeash = null;
- }
+ clearChangeLeash(getPendingTransaction(), true /* cancel */);
}
/**
@@ -2830,6 +2975,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
if (mPendingRelaunchCount != 0) {
pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount);
}
+ if (mSizeCompatScale != 1f || mSizeCompatBounds != null) {
+ pw.println(prefix + "mSizeCompatScale=" + mSizeCompatScale + " mSizeCompatBounds="
+ + mSizeCompatBounds);
+ }
if (mRemovingFromDisplay) {
pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay);
}
@@ -3003,7 +3152,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
void removeFromPendingTransition() {
if (isWaitingForTransitionStart() && mDisplayContent != null) {
mDisplayContent.mOpeningApps.remove(this);
- mDisplayContent.mChangingApps.remove(this);
+ if (mDisplayContent.mChangingApps.remove(this)) {
+ clearChangeLeash(getPendingTransaction(), true /* cancel */);
+ }
mDisplayContent.mClosingApps.remove(this);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 5cfc20b6339f..4795555e8ed2 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1500,8 +1500,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
final int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / mBaseDisplayDensity;
final int longSizeDp = longSize * DisplayMetrics.DENSITY_DEFAULT / mBaseDisplayDensity;
- mDisplayRotation.configure(width, height, shortSizeDp, longSizeDp);
mDisplayPolicy.configure(width, height, shortSizeDp);
+ mDisplayRotation.configure(width, height, shortSizeDp, longSizeDp);
mDisplayFrames.onDisplayInfoUpdated(mDisplayInfo,
calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 2ee30ac5c8ff..91d573defc16 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2617,9 +2617,8 @@ public class DisplayPolicy {
DisplayCutout displayCutout) {
int width = fullWidth;
if (hasNavigationBar()) {
- // For a basic navigation bar, when we are in landscape mode we place
- // the navigation bar to the side.
- if (navigationBarCanMove() && fullWidth > fullHeight) {
+ final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
+ if (navBarPosition == NAV_BAR_LEFT || navBarPosition == NAV_BAR_RIGHT) {
width -= getNavigationBarWidth(rotation, uiMode);
}
}
@@ -2646,9 +2645,8 @@ public class DisplayPolicy {
DisplayCutout displayCutout) {
int height = fullHeight;
if (hasNavigationBar()) {
- // For a basic navigation bar, when we are in portrait mode we place
- // the navigation bar to the bottom.
- if (!navigationBarCanMove() || fullWidth < fullHeight) {
+ final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
+ if (navBarPosition == NAV_BAR_BOTTOM) {
height -= getNavigationBarHeight(rotation, uiMode);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 5f341ee8002c..543f19655350 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -38,6 +38,7 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
import android.util.SparseArray;
+import android.view.DisplayCutout;
import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;
@@ -70,6 +71,8 @@ public class DisplayRotation {
private final int mDeskDockRotation;
private final int mUndockedHdmiRotation;
+ private final float mCloseToSquareMaxAspectRatio;
+
private OrientationListener mOrientationListener;
private StatusBarManagerInternal mStatusBarManagerInternal;
private SettingsObserver mSettingsObserver;
@@ -132,6 +135,9 @@ public class DisplayRotation {
mUndockedHdmiRotation = readRotation(
com.android.internal.R.integer.config_undockedHdmiRotation);
+ mCloseToSquareMaxAspectRatio = mContext.getResources().getFloat(
+ com.android.internal.R.dimen.config_closeToSquareDisplayMaxAspectRatio);
+
if (isDefaultDisplay) {
final Handler uiHandler = UiThread.getHandler();
mOrientationListener = new OrientationListener(mContext, uiHandler);
@@ -212,10 +218,12 @@ public class DisplayRotation {
// so if the orientation is forced, we need to respect that no matter what.
final boolean isTv = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_LEANBACK);
+ final boolean isCloseToSquare =
+ isNonDecorDisplayCloseToSquare(Surface.ROTATION_0, width, height);
final boolean forceDefaultOrientationInRes =
res.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation);
final boolean forceDefaultOrienation =
- ((longSizeDp >= 960 && shortSizeDp >= 720) || isCar || isTv)
+ ((longSizeDp >= 960 && shortSizeDp >= 720) || isCar || isTv || isCloseToSquare)
&& forceDefaultOrientationInRes
// For debug purposes the next line turns this feature off with:
// $ adb shell setprop config.override_forced_orient true
@@ -227,6 +235,18 @@ public class DisplayRotation {
setFixedToUserRotation(forceDefaultOrienation);
}
+ private boolean isNonDecorDisplayCloseToSquare(int rotation, int width, int height) {
+ final DisplayCutout displayCutout =
+ mDisplayContent.calculateDisplayCutoutForRotation(rotation).getDisplayCutout();
+ final int uiMode = mService.mPolicy.getUiMode();
+ final int w = mDisplayPolicy.getNonDecorDisplayWidth(
+ width, height, rotation, uiMode, displayCutout);
+ final int h = mDisplayPolicy.getNonDecorDisplayHeight(
+ width, height, rotation, uiMode, displayCutout);
+ final float aspectRatio = Math.max(w, h) / (float) Math.min(w, h);
+ return aspectRatio <= mCloseToSquareMaxAspectRatio;
+ }
+
void setRotation(int rotation) {
if (mOrientationListener != null) {
mOrientationListener.setCurrentRotation(rotation);
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index f9c9d33c561a..f46835eb51fc 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -163,15 +163,12 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
}
- /**
- * Provides an opportunity for the window manager policy to intercept early motion event
- * processing when the device is in a non-interactive state since these events are normally
- * dropped.
- */
+ /** {@inheritDoc} */
@Override
- public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
+ public int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
+ int policyFlags) {
return mService.mPolicy.interceptMotionBeforeQueueingNonInteractive(
- whenNanos, policyFlags);
+ displayId, whenNanos, policyFlags);
}
/**
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 987492024546..d67193ea9e69 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -20,7 +20,15 @@ import static android.view.SurfaceControl.HIDDEN;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.Binder;
+import android.os.Process;
+import android.view.InputChannel;
+import android.view.InputEventReceiver;
+import android.view.InputWindowHandle;
import android.view.SurfaceControl;
+import android.view.WindowManager;
+
+import com.android.server.UiThread;
import java.util.function.Supplier;
@@ -40,6 +48,7 @@ public class Letterbox {
private final LetterboxSurface mLeft = new LetterboxSurface("left");
private final LetterboxSurface mBottom = new LetterboxSurface("bottom");
private final LetterboxSurface mRight = new LetterboxSurface("right");
+ private final LetterboxSurface[] mSurfaces = { mLeft, mTop, mRight, mBottom };
/**
* Constructs a Letterbox.
@@ -87,8 +96,12 @@ public class Letterbox {
* Returns true if any part of the letterbox overlaps with the given {@code rect}.
*/
public boolean isOverlappingWith(Rect rect) {
- return mTop.isOverlappingWith(rect) || mLeft.isOverlappingWith(rect)
- || mBottom.isOverlappingWith(rect) || mRight.isOverlappingWith(rect);
+ for (LetterboxSurface surface : mSurfaces) {
+ if (surface.isOverlappingWith(rect)) {
+ return true;
+ }
+ }
+ return false;
}
/**
@@ -107,25 +120,94 @@ public class Letterbox {
mOuter.setEmpty();
mInner.setEmpty();
- mTop.remove();
- mLeft.remove();
- mBottom.remove();
- mRight.remove();
+ for (LetterboxSurface surface : mSurfaces) {
+ surface.remove();
+ }
}
/** Returns whether a call to {@link #applySurfaceChanges} would change the surface. */
public boolean needsApplySurfaceChanges() {
- return mTop.needsApplySurfaceChanges()
- || mLeft.needsApplySurfaceChanges()
- || mBottom.needsApplySurfaceChanges()
- || mRight.needsApplySurfaceChanges();
+ for (LetterboxSurface surface : mSurfaces) {
+ if (surface.needsApplySurfaceChanges()) {
+ return true;
+ }
+ }
+ return false;
}
public void applySurfaceChanges(SurfaceControl.Transaction t) {
- mTop.applySurfaceChanges(t);
- mLeft.applySurfaceChanges(t);
- mBottom.applySurfaceChanges(t);
- mRight.applySurfaceChanges(t);
+ for (LetterboxSurface surface : mSurfaces) {
+ surface.applySurfaceChanges(t);
+ }
+ }
+
+ /** Enables touches to slide into other neighboring surfaces. */
+ void attachInput(WindowState win) {
+ for (LetterboxSurface surface : mSurfaces) {
+ surface.attachInput(win);
+ }
+ }
+
+ void onMovedToDisplay(int displayId) {
+ for (LetterboxSurface surface : mSurfaces) {
+ if (surface.mInputInterceptor != null) {
+ surface.mInputInterceptor.mWindowHandle.displayId = displayId;
+ }
+ }
+ }
+
+ private static class InputInterceptor {
+ final InputChannel mServerChannel;
+ final InputChannel mClientChannel;
+ final InputWindowHandle mWindowHandle;
+ final InputEventReceiver mInputEventReceiver;
+ final WindowManagerService mWmService;
+
+ InputInterceptor(String namePrefix, WindowState win) {
+ mWmService = win.mWmService;
+ final String name = namePrefix + (win.mAppToken != null ? win.mAppToken : win);
+ final InputChannel[] channels = InputChannel.openInputChannelPair(name);
+ mServerChannel = channels[0];
+ mClientChannel = channels[1];
+ mInputEventReceiver = new SimpleInputReceiver(mClientChannel);
+
+ final Binder token = new Binder();
+ mWmService.mInputManager.registerInputChannel(mServerChannel, token);
+
+ mWindowHandle = new InputWindowHandle(null /* inputApplicationHandle */,
+ null /* clientWindow */, win.getDisplayId());
+ mWindowHandle.name = name;
+ mWindowHandle.token = token;
+ mWindowHandle.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
+ | WindowManager.LayoutParams.FLAG_SLIPPERY;
+ mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
+ mWindowHandle.dispatchingTimeoutNanos =
+ WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mWindowHandle.visible = true;
+ mWindowHandle.ownerPid = Process.myPid();
+ mWindowHandle.ownerUid = Process.myUid();
+ mWindowHandle.scaleFactor = 1.0f;
+ }
+
+ void updateTouchableRegion(Rect frame) {
+ mWindowHandle.touchableRegion.set(frame);
+ mWindowHandle.touchableRegion.translate(-frame.left, -frame.top);
+ }
+
+ void dispose() {
+ mWmService.mInputManager.unregisterInputChannel(mServerChannel);
+ mInputEventReceiver.dispose();
+ mServerChannel.dispose();
+ mClientChannel.dispose();
+ }
+
+ private static class SimpleInputReceiver extends InputEventReceiver {
+ SimpleInputReceiver(InputChannel inputChannel) {
+ super(inputChannel, UiThread.getHandler().getLooper());
+ }
+ }
}
private class LetterboxSurface {
@@ -137,6 +219,8 @@ public class Letterbox {
private final Rect mLayoutFrameGlobal = new Rect();
private final Rect mLayoutFrameRelative = new Rect();
+ private InputInterceptor mInputInterceptor;
+
public LetterboxSurface(String type) {
mType = type;
}
@@ -154,11 +238,22 @@ public class Letterbox {
mSurface.setColor(new float[]{0, 0, 0});
}
+ void attachInput(WindowState win) {
+ if (mInputInterceptor != null) {
+ mInputInterceptor.dispose();
+ }
+ mInputInterceptor = new InputInterceptor("Letterbox_" + mType + "_", win);
+ }
+
public void remove() {
if (mSurface != null) {
mSurface.remove();
mSurface = null;
}
+ if (mInputInterceptor != null) {
+ mInputInterceptor.dispose();
+ mInputInterceptor = null;
+ }
}
public int getWidth() {
@@ -193,6 +288,10 @@ public class Letterbox {
t.setPosition(mSurface, mSurfaceFrameRelative.left, mSurfaceFrameRelative.top);
t.setWindowCrop(mSurface, mSurfaceFrameRelative.width(),
mSurfaceFrameRelative.height());
+ if (mInputInterceptor != null) {
+ mInputInterceptor.updateTouchableRegion(mSurfaceFrameRelative);
+ t.setInputWindowInfo(mSurface, mInputInterceptor.mWindowHandle);
+ }
t.show(mSurface);
} else if (mSurface != null) {
t.hide(mSurface);
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index fb5b1d85a4a2..5c91d9e6fff2 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -300,7 +300,7 @@ class RootActivityContainer extends ConfigurationContainer
* corresponding record in display manager.
*/
// TODO: Look into consolidating with getActivityDisplay()
- ActivityDisplay getActivityDisplayOrCreate(int displayId) {
+ @Nullable ActivityDisplay getActivityDisplayOrCreate(int displayId) {
ActivityDisplay activityDisplay = getActivityDisplay(displayId);
if (activityDisplay != null) {
return activityDisplay;
@@ -1317,6 +1317,9 @@ class RootActivityContainer extends ConfigurationContainer
if (DEBUG_STACK) Slog.v(TAG, "Display added displayId=" + displayId);
synchronized (mService.mGlobalLock) {
final ActivityDisplay display = getActivityDisplayOrCreate(displayId);
+ if (display == null) {
+ return;
+ }
// Do not start home before booting, or it may accidentally finish booting before it
// starts. Instead, we expect home activities to be launched when the system is ready
// (ActivityManagerService#systemReady).
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 5ea24518370b..35b8641371be 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -251,7 +251,7 @@ class SurfaceAnimator {
if (DEBUG_ANIM) Slog.i(TAG, "Cancelling animation restarting=" + restarting);
final SurfaceControl leash = mLeash;
final AnimationAdapter animation = mAnimation;
- reset(t, forwardCancel);
+ reset(t, false);
if (animation != null) {
if (!mAnimationStartDelayed && forwardCancel) {
animation.onAnimationCancelled(leash);
@@ -260,6 +260,12 @@ class SurfaceAnimator {
mAnimationFinishedCallback.run();
}
}
+
+ if (forwardCancel && leash != null) {
+ t.remove(leash);
+ mService.scheduleAnimationLocked();
+ }
+
if (!restarting) {
mAnimationStartDelayed = false;
}
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 69f0012b69ba..59d7560fc5b0 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -119,6 +119,7 @@ import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
+import android.view.Display;
import android.view.DisplayInfo;
import com.android.internal.annotations.VisibleForTesting;
@@ -1288,22 +1289,7 @@ class TaskRecord extends ConfigurationContainer {
|| top == null) {
return getRequestedOverrideConfiguration().orientation;
}
- int screenOrientation = top.getOrientation();
- if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
- // NOSENSOR means the display's "natural" orientation, so return that.
- ActivityDisplay display = mStack != null ? mStack.getDisplay() : null;
- if (display != null && display.mDisplayContent != null) {
- return mStack.getDisplay().mDisplayContent.getNaturalOrientation();
- }
- } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
- // LOCKED means the activity's orientation remains unchanged, so return existing value.
- return top.getConfiguration().orientation;
- } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation)) {
- return ORIENTATION_LANDSCAPE;
- } else if (ActivityInfo.isFixedOrientationPortrait(screenOrientation)) {
- return ORIENTATION_PORTRAIT;
- }
- return ORIENTATION_UNDEFINED;
+ return top.getRequestedConfigurationOrientation();
}
/**
@@ -2084,6 +2070,11 @@ class TaskRecord extends ConfigurationContainer {
return Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
}
+ void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
+ @NonNull Configuration parentConfig) {
+ computeConfigResourceOverrides(inOutConfig, parentConfig, true /* insideParentBounds */);
+ }
+
/**
* Calculates configuration values used by the client to get resources. This should be run
* using app-facing bounds (bounds unmodified by animations or transient interactions).
@@ -2093,7 +2084,7 @@ class TaskRecord extends ConfigurationContainer {
* just be inherited from the parent configuration.
**/
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
- @NonNull Configuration parentConfig) {
+ @NonNull Configuration parentConfig, boolean insideParentBounds) {
int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
if (windowingMode == WINDOWING_MODE_UNDEFINED) {
windowingMode = parentConfig.windowConfiguration.getWindowingMode();
@@ -2111,7 +2102,7 @@ class TaskRecord extends ConfigurationContainer {
inOutConfig.windowConfiguration.setAppBounds(bounds);
outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
}
- if (windowingMode != WINDOWING_MODE_FREEFORM) {
+ if (insideParentBounds && windowingMode != WINDOWING_MODE_FREEFORM) {
final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds();
if (parentAppBounds != null && !parentAppBounds.isEmpty()) {
outAppBounds.intersect(parentAppBounds);
@@ -2120,7 +2111,7 @@ class TaskRecord extends ConfigurationContainer {
if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED
|| inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
- if (mStack != null) {
+ if (insideParentBounds && mStack != null) {
final DisplayInfo di = new DisplayInfo();
mStack.getDisplay().mDisplay.getDisplayInfo(di);
@@ -2135,12 +2126,16 @@ class TaskRecord extends ConfigurationContainer {
}
if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
- inOutConfig.screenWidthDp = Math.min((int) (mTmpStableBounds.width() / density),
- parentConfig.screenWidthDp);
+ final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density);
+ inOutConfig.screenWidthDp = insideParentBounds
+ ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp)
+ : overrideScreenWidthDp;
}
if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
- inOutConfig.screenHeightDp = Math.min((int) (mTmpStableBounds.height() / density),
- parentConfig.screenHeightDp);
+ final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density);
+ inOutConfig.screenHeightDp = insideParentBounds
+ ? Math.min(overrideScreenHeightDp, parentConfig.screenWidthDp)
+ : overrideScreenHeightDp;
}
if (inOutConfig.smallestScreenWidthDp
@@ -2162,7 +2157,7 @@ class TaskRecord extends ConfigurationContainer {
if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
- ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
+ ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
}
if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
// For calculating screen layout, we need to use the non-decor inset screen area for the
@@ -2332,6 +2327,7 @@ class TaskRecord extends ConfigurationContainer {
info.userId = userId;
info.stackId = getStackId();
info.taskId = taskId;
+ info.displayId = mStack == null ? Display.INVALID_DISPLAY : mStack.mDisplayId;
info.isRunning = getTopActivity() != null;
info.baseIntent = new Intent(getBaseIntent());
info.baseActivity = reuseActivitiesReport.base != null
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6c3e1f4ce1c2..168c9adb61be 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -47,7 +47,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
@@ -188,6 +187,7 @@ import android.util.SparseBooleanArray;
import android.util.TimeUtils;
import android.util.TypedValue;
import android.util.proto.ProtoOutputStream;
+import android.view.Choreographer;
import android.view.Display;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
@@ -446,7 +446,8 @@ public class WindowManagerService extends IWindowManager.Stub
final boolean mLimitedAlphaCompositing;
final int mMaxUiWidth;
- final WindowManagerPolicy mPolicy;
+ @VisibleForTesting
+ WindowManagerPolicy mPolicy;
final IActivityManager mActivityManager;
// TODO: Probably not needed once activities are fully in WM.
@@ -843,7 +844,7 @@ public class WindowManagerService extends IWindowManager.Stub
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "closeSurfaceTransaction");
synchronized (mGlobalLock) {
SurfaceControl.closeTransaction();
- traceStateLocked(where);
+ mWindowTracing.logState(where);
}
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
@@ -967,7 +968,8 @@ public class WindowManagerService extends IWindowManager.Stub
mWindowPlacerLocked = new WindowSurfacePlacer(this);
mTaskSnapshotController = new TaskSnapshotController(this);
- mWindowTracing = WindowTracing.createDefaultAndStartLooper(context);
+ mWindowTracing = WindowTracing.createDefaultAndStartLooper(this,
+ Choreographer.getInstance());
LocalServices.addService(WindowManagerPolicy.class, mPolicy);
@@ -1837,6 +1839,9 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
outDisplayFrame.set(win.getDisplayFrameLw());
+ if (win.inSizeCompatMode()) {
+ outDisplayFrame.scale(win.mInvGlobalScale);
+ }
}
}
@@ -1961,8 +1966,6 @@ public class WindowManagerService extends IWindowManager.Stub
if (DEBUG_LAYOUT) Slog.v(TAG_WM, "Relayout " + win + ": viewVisibility=" + viewVisibility
+ " req=" + requestedWidth + "x" + requestedHeight + " " + win.mAttrs);
winAnimator.mSurfaceDestroyDeferred = (flags & RELAYOUT_DEFER_SURFACE_DESTROY) != 0;
- win.mEnforceSizeCompat =
- (win.mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0;
if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) {
winAnimator.mAlpha = attrs.alpha;
}
@@ -4261,9 +4264,12 @@ public class WindowManagerService extends IWindowManager.Stub
if (mMaxUiWidth > 0) {
mRoot.forAllDisplays(displayContent -> displayContent.setMaxUiWidth(mMaxUiWidth));
}
- applyForcedPropertiesForDefaultDisplay();
+ final boolean changed = applyForcedPropertiesForDefaultDisplay();
mAnimator.ready();
mDisplayReady = true;
+ if (changed) {
+ reconfigureDisplayLocked(getDefaultDisplayContentLocked());
+ }
mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TOUCHSCREEN);
}
@@ -4863,7 +4869,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
/** The global settings only apply to default display. */
- private void applyForcedPropertiesForDefaultDisplay() {
+ private boolean applyForcedPropertiesForDefaultDisplay() {
+ boolean changed = false;
final DisplayContent displayContent = getDefaultDisplayContentLocked();
// Display size.
String sizeStr = Settings.Global.getString(mContext.getContentResolver(),
@@ -4883,6 +4890,7 @@ public class WindowManagerService extends IWindowManager.Stub
Slog.i(TAG_WM, "FORCED DISPLAY SIZE: " + width + "x" + height);
displayContent.updateBaseDisplayMetrics(width, height,
displayContent.mBaseDisplayDensity);
+ changed = true;
}
} catch (NumberFormatException ex) {
}
@@ -4891,17 +4899,20 @@ public class WindowManagerService extends IWindowManager.Stub
// Display density.
final int density = getForcedDisplayDensityForUserLocked(mCurrentUserId);
- if (density != 0) {
+ if (density != 0 && density != displayContent.mBaseDisplayDensity) {
displayContent.mBaseDisplayDensity = density;
+ changed = true;
}
// Display scaling mode.
int mode = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.DISPLAY_SCALING_FORCE, 0);
- if (mode != 0) {
+ if (displayContent.mDisplayScalingDisabled != (mode != 0)) {
Slog.i(TAG_WM, "FORCED DISPLAY SCALING DISABLED");
displayContent.mDisplayScalingDisabled = true;
+ changed = true;
}
+ return changed;
}
@Override
@@ -5765,17 +5776,6 @@ public class WindowManagerService extends IWindowManager.Stub
proto.write(LAST_ORIENTATION, defaultDisplayContent.getLastOrientation());
}
- void traceStateLocked(String where) {
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "traceStateLocked");
- try {
- mWindowTracing.traceStateLocked(where, this);
- } catch (Exception e) {
- Log.wtf(TAG, "Exception while tracing state", e);
- } finally {
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- }
- }
-
private void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
ArrayList<WindowState> windows) {
pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 85b251a99f83..3430987f4736 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -246,7 +246,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
final boolean mIsWallpaper;
private final boolean mIsFloatingLayer;
int mSeq;
- boolean mEnforceSizeCompat;
int mViewVisibility;
int mSystemUiVisibility;
/**
@@ -505,7 +504,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
*/
private PowerManager.WakeLock mDrawLock;
- final private Rect mTmpRect = new Rect();
+ private final Rect mTmpRect = new Rect();
+ private final Point mTmpPoint = new Point();
/**
* Whether the window was resized by us while it was gone for layout.
@@ -655,7 +655,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mContext = mWmService.mContext;
DeathRecipient deathRecipient = new DeathRecipient();
mSeq = seq;
- mEnforceSizeCompat = (mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0;
mPowerManagerWrapper = powerManagerWrapper;
mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
if (localLOGV) Slog.v(
@@ -733,6 +732,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
/**
+ * @return {@code true} if the application runs in size compatibility mode.
+ * @see android.content.res.CompatibilityInfo#supportsScreen
+ * @see ActivityRecord#inSizeCompatMode
+ */
+ boolean inSizeCompatMode() {
+ return (mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0
+ || (mAppToken != null && mAppToken.inSizeCompatMode()
+ // Exclude starting window because it is not displayed by the application.
+ && mAttrs.type != TYPE_APPLICATION_STARTING);
+ }
+
+ /**
* Returns whether this {@link WindowState} has been considered for drawing by its parent.
*/
boolean getDrawnStateEvaluated() {
@@ -995,7 +1006,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mWindowFrames.offsetFrames(-layoutXDiff, -layoutYDiff);
mWindowFrames.mCompatFrame.set(mWindowFrames.mFrame);
- if (mEnforceSizeCompat) {
+ if (inSizeCompatMode()) {
// If there is a size compatibility scale being applied to the
// window, we need to apply this to its insets so that they are
// reported to the app in its coordinate space.
@@ -1354,8 +1365,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
void prelayout() {
- if (mEnforceSizeCompat) {
- mGlobalScale = getDisplayContent().mCompatibleScreenScale;
+ if (inSizeCompatMode()) {
+ mGlobalScale = mToken.getSizeCompatScale();
mInvGlobalScale = 1 / mGlobalScale;
} else {
mGlobalScale = mInvGlobalScale = 1;
@@ -2145,6 +2156,30 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
int getSurfaceTouchableRegion(Region region, int flags) {
final boolean modal = (flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0;
+ if (mAppToken != null && !mAppToken.getResolvedOverrideBounds().isEmpty()) {
+ // There may have touchable letterboxes around the activity, so in order to let the
+ // letterboxes are able to receive touch event and slip to activity, the activity with
+ // compatibility bounds cannot occupy full screen touchable region.
+ if (modal) {
+ // A modal window uses the whole compatibility bounds.
+ flags |= FLAG_NOT_TOUCH_MODAL;
+ mTmpRect.set(mAppToken.getResolvedOverrideBounds());
+ // TODO(b/112288258): Remove the forced offset when the override bounds always
+ // starts from zero (See {@link ActivityRecord#resolveOverrideConfiguration}).
+ mTmpRect.offsetTo(0, 0);
+ } else {
+ // Non-modal uses the application based frame.
+ mTmpRect.set(mWindowFrames.mCompatFrame);
+ }
+ // The offset of compatibility bounds is applied to surface of {@link #AppWindowToken}
+ // and frame, so it is unnecessary to translate twice in surface based coordinates.
+ final int surfaceOffsetX = mAppToken.inSizeCompatMode()
+ ? mAppToken.getBounds().left : 0;
+ mTmpRect.offset(surfaceOffsetX - mWindowFrames.mFrame.left, -mWindowFrames.mFrame.top);
+ region.set(mTmpRect);
+ return flags;
+ }
+
if (modal && mAppToken != null) {
// Limit the outer touch to the activity stack region.
flags |= FLAG_NOT_TOUCH_MODAL;
@@ -2431,7 +2466,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
/** @return false if this window desires touch events. */
boolean cantReceiveTouchInput() {
return mAppToken != null && mAppToken.getTask() != null
- && mAppToken.getTask().mStack.shouldIgnoreInput();
+ && (mAppToken.getTask().mStack.shouldIgnoreInput() || mAppToken.hiddenRequested);
}
@Override
@@ -2943,7 +2978,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == DRAW_PENDING)
Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING");
- final Rect frame = mWindowFrames.mFrame;
+ final Rect frame = mWindowFrames.mCompatFrame;
final Rect overscanInsets = mWindowFrames.mLastOverscanInsets;
final Rect contentInsets = mWindowFrames.mLastContentInsets;
final Rect visibleInsets = mWindowFrames.mLastVisibleInsets;
@@ -3353,7 +3388,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
pw.println(prefix + "mHasSurface=" + mHasSurface
+ " isReadyForDisplay()=" + isReadyForDisplay()
+ " mWindowRemovalAllowed=" + mWindowRemovalAllowed);
- if (mEnforceSizeCompat) {
+ if (inSizeCompatMode()) {
pw.println(prefix + "mCompatFrame=" + mWindowFrames.mCompatFrame.toShortString(sTmpSB));
}
if (dumpAll) {
@@ -3477,17 +3512,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
float x, y;
int w,h;
+ final boolean inSizeCompatMode = inSizeCompatMode();
if ((mAttrs.flags & FLAG_SCALED) != 0) {
if (mAttrs.width < 0) {
w = pw;
- } else if (mEnforceSizeCompat) {
+ } else if (inSizeCompatMode) {
w = (int)(mAttrs.width * mGlobalScale + .5f);
} else {
w = mAttrs.width;
}
if (mAttrs.height < 0) {
h = ph;
- } else if (mEnforceSizeCompat) {
+ } else if (inSizeCompatMode) {
h = (int)(mAttrs.height * mGlobalScale + .5f);
} else {
h = mAttrs.height;
@@ -3495,21 +3531,21 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
} else {
if (mAttrs.width == MATCH_PARENT) {
w = pw;
- } else if (mEnforceSizeCompat) {
+ } else if (inSizeCompatMode) {
w = (int)(mRequestedWidth * mGlobalScale + .5f);
} else {
w = mRequestedWidth;
}
if (mAttrs.height == MATCH_PARENT) {
h = ph;
- } else if (mEnforceSizeCompat) {
+ } else if (inSizeCompatMode) {
h = (int)(mRequestedHeight * mGlobalScale + .5f);
} else {
h = mRequestedHeight;
}
}
- if (mEnforceSizeCompat) {
+ if (inSizeCompatMode) {
x = mAttrs.x * mGlobalScale;
y = mAttrs.y * mGlobalScale;
} else {
@@ -3537,7 +3573,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// We need to make sure we update the CompatFrame as it is used for
// cropping decisions, etc, on systems where we lack a decor layer.
mWindowFrames.mCompatFrame.set(mWindowFrames.mFrame);
- if (mEnforceSizeCompat) {
+ if (inSizeCompatMode) {
// See comparable block in computeFrameLw.
mWindowFrames.mCompatFrame.scale(mInvGlobalScale);
}
@@ -3650,7 +3686,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
float translateToWindowX(float x) {
float winX = x - mWindowFrames.mFrame.left;
- if (mEnforceSizeCompat) {
+ if (inSizeCompatMode()) {
winX *= mGlobalScale;
}
return winX;
@@ -3658,7 +3694,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
float translateToWindowY(float y) {
float winY = y - mWindowFrames.mFrame.top;
- if (mEnforceSizeCompat) {
+ if (inSizeCompatMode()) {
winY *= mGlobalScale;
}
return winY;
@@ -4233,12 +4269,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
*/
void calculatePolicyCrop(Rect policyCrop) {
final DisplayContent displayContent = getDisplayContent();
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- if (!isDefaultDisplay()) {
+ if (!displayContent.isDefaultDisplay && !displayContent.supportsSystemDecorations()) {
// On a different display there is no system decor. Crop the window
// by the screen boundaries.
- // TODO(multi-display)
+ final DisplayInfo displayInfo = displayContent.getDisplayInfo();
policyCrop.set(0, 0, mWindowFrames.mCompatFrame.width(),
mWindowFrames.mCompatFrame.height());
policyCrop.intersect(-mWindowFrames.mCompatFrame.left, -mWindowFrames.mCompatFrame.top,
@@ -4304,7 +4339,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// scale function because we want to round things to make the crop
// always round to a larger rect to ensure we don't crop too
// much and hide part of the window that should be seen.
- if (mEnforceSizeCompat && mInvGlobalScale != 1.0f) {
+ if (inSizeCompatMode() && mInvGlobalScale != 1.0f) {
final float scale = mInvGlobalScale;
systemDecorRect.left = (int) (systemDecorRect.left * scale - 0.5f);
systemDecorRect.top = (int) (systemDecorRect.top * scale - 0.5f);
@@ -4664,8 +4699,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// Since the parent was outset by its surface insets, we need to undo the outsetting
// with insetting by the same amount.
final WindowState parent = getParentWindow();
- outPoint.offset(-parent.mWindowFrames.mFrame.left + parent.mAttrs.surfaceInsets.left,
- -parent.mWindowFrames.mFrame.top + parent.mAttrs.surfaceInsets.top);
+ transformSurfaceInsetsPosition(mTmpPoint, parent.mAttrs.surfaceInsets);
+ outPoint.offset(-parent.mWindowFrames.mFrame.left + mTmpPoint.x,
+ -parent.mWindowFrames.mFrame.top + mTmpPoint.y);
} else if (parentWindowContainer != null) {
final Rect parentBounds = parentWindowContainer.getDisplayedBounds();
outPoint.offset(-parentBounds.left, -parentBounds.top);
@@ -4683,7 +4719,22 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
// Expand for surface insets. See WindowState.expandForSurfaceInsets.
- outPoint.offset(-mAttrs.surfaceInsets.left, -mAttrs.surfaceInsets.top);
+ transformSurfaceInsetsPosition(mTmpPoint, mAttrs.surfaceInsets);
+ outPoint.offset(-mTmpPoint.x, -mTmpPoint.y);
+ }
+
+ /**
+ * The surface insets from layout parameter are in application coordinate. If the window is
+ * scaled, the insets also need to be scaled for surface position in global coordinate.
+ */
+ private void transformSurfaceInsetsPosition(Point outPos, Rect surfaceInsets) {
+ if (!inSizeCompatMode()) {
+ outPos.x = surfaceInsets.left;
+ outPos.y = surfaceInsets.top;
+ return;
+ }
+ outPos.x = (int) (surfaceInsets.left * mGlobalScale + 0.5f);
+ outPos.y = (int) (surfaceInsets.top * mGlobalScale + 0.5f);
}
boolean needsRelativeLayeringToIme() {
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 3b9b8bab9e61..f0b9c62f2843 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -182,6 +182,14 @@ class WindowToken extends WindowContainer<WindowState> {
}
/**
+ * @return The scale for applications running in compatibility mode. Multiply the size in the
+ * application by this scale will be the size in the screen.
+ */
+ float getSizeCompatScale() {
+ return mDisplayContent.mCompatibleScreenScale;
+ }
+
+ /**
* Returns true if the new window is considered greater than the existing window in terms of
* z-order.
*/
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index 8b1ffa8387d7..abc474d756b7 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -24,12 +24,14 @@ import static com.android.server.wm.WindowManagerTraceProto.WHERE;
import static com.android.server.wm.WindowManagerTraceProto.WINDOW_MANAGER_SERVICE;
import android.annotation.Nullable;
-import android.content.Context;
import android.os.ShellCommand;
import android.os.SystemClock;
import android.os.Trace;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
+import android.view.Choreographer;
+
+import com.android.internal.annotations.VisibleForTesting;
import java.io.File;
import java.io.IOException;
@@ -48,6 +50,10 @@ class WindowTracing {
private static final int WINDOW_TRACE_BUFFER_SIZE = 512 * 1024;
private static final String TAG = "WindowTracing";
+ private final WindowManagerService mService;
+ private final Choreographer mChoreographer;
+ private final WindowManagerGlobalLock mGlobalLock;
+
private final Object mLock = new Object();
private final WindowTraceBuffer.Builder mBufferBuilder;
@@ -57,11 +63,24 @@ class WindowTracing {
private boolean mContinuousMode;
private boolean mEnabled;
private volatile boolean mEnabledLockFree;
+ private boolean mScheduled;
+ private Choreographer.FrameCallback mFrameCallback = (frameTimeNanos) ->
+ log("onFrame" /* where */);
+
+ private WindowTracing(File file, WindowManagerService service, Choreographer choreographer) {
+ this(file, service, choreographer, service.mGlobalLock);
+ }
- WindowTracing(File file) {
+ @VisibleForTesting
+ WindowTracing(File file, WindowManagerService service, Choreographer choreographer,
+ WindowManagerGlobalLock globalLock) {
mBufferBuilder = new WindowTraceBuffer.Builder()
.setTraceFile(file)
.setBufferCapacity(WINDOW_TRACE_BUFFER_SIZE);
+
+ mChoreographer = choreographer;
+ mService = service;
+ mGlobalLock = globalLock;
}
void startTrace(@Nullable PrintWriter pw) throws IOException {
@@ -111,7 +130,8 @@ class WindowTracing {
}
}
- private void setContinuousMode(boolean continuous, PrintWriter pw) {
+ @VisibleForTesting
+ void setContinuousMode(boolean continuous, PrintWriter pw) {
logAndPrintln(pw, "Setting window tracing continuous mode to " + continuous);
if (mEnabled) {
@@ -123,21 +143,14 @@ class WindowTracing {
WindowTraceLogLevel.TRIM;
}
- private void appendTraceEntry(ProtoOutputStream proto) {
- if (!mEnabledLockFree) {
- return;
- }
-
- mTraceBuffer.add(proto);
- }
-
boolean isEnabled() {
return mEnabledLockFree;
}
- static WindowTracing createDefaultAndStartLooper(Context context) {
+ static WindowTracing createDefaultAndStartLooper(WindowManagerService service,
+ Choreographer choreographer) {
File file = new File("/data/misc/wmtrace/wm_trace.pb");
- return new WindowTracing(file);
+ return new WindowTracing(file, service, choreographer);
}
int onShellCommand(ShellCommand shell) {
@@ -164,28 +177,65 @@ class WindowTracing {
}
}
- void traceStateLocked(String where, WindowManagerService service) {
+ /**
+ * If tracing is enabled, log the current state or schedule the next frame to be logged,
+ * according to {@link #mContinuousMode}.
+ *
+ * @param where Logging point descriptor
+ */
+ void logState(String where) {
if (!isEnabled()) {
return;
}
- Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToBufferLocked");
+ if (mContinuousMode) {
+ schedule();
+ } else {
+ log(where);
+ }
+ }
+
+ /**
+ * Schedule the log to trace the next frame
+ */
+ private void schedule() {
+ if (mScheduled) {
+ return;
+ }
+
+ mScheduled = true;
+ mChoreographer.postFrameCallback(mFrameCallback);
+ }
+
+ /**
+ * Write the current frame to the buffer
+ *
+ * @param where Logging point descriptor
+ */
+ private void log(String where) {
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "traceStateLocked");
try {
- ProtoOutputStream os = new ProtoOutputStream();
- long tokenOuter = os.start(ENTRY);
- os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
- os.write(WHERE, where);
-
- Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToProtoLocked");
- try {
- long tokenInner = os.start(WINDOW_MANAGER_SERVICE);
- service.writeToProtoLocked(os, mWindowTraceLogLevel);
- os.end(tokenInner);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ synchronized (mGlobalLock) {
+ ProtoOutputStream os = new ProtoOutputStream();
+ long tokenOuter = os.start(ENTRY);
+ os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
+ os.write(WHERE, where);
+
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToProtoLocked");
+ try {
+ long tokenInner = os.start(WINDOW_MANAGER_SERVICE);
+ mService.writeToProtoLocked(os, mWindowTraceLogLevel);
+ os.end(tokenInner);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ }
+ os.end(tokenOuter);
+ mTraceBuffer.add(os);
+
+ mScheduled = false;
}
- os.end(tokenOuter);
- appendTraceEntry(os);
+ } catch (Exception e) {
+ Log.wtf(TAG, "Exception while tracing state", e);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index 5c19ad33617c..9cbb58d35b9f 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "BatteryStatsService"
//#define LOG_NDEBUG 0
+#include <climits>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
@@ -28,6 +29,7 @@
#include <sys/types.h>
#include <unistd.h>
#include <unordered_map>
+#include <utility>
#include <android/hardware/power/1.0/IPower.h>
#include <android/hardware/power/1.1/IPower.h>
@@ -87,6 +89,15 @@ std::function<void(JNIEnv*, jobject)> gGetLowPowerStatsImpl = {};
std::function<jint(JNIEnv*, jobject)> gGetPlatformLowPowerStatsImpl = {};
std::function<jint(JNIEnv*, jobject)> gGetSubsystemLowPowerStatsImpl = {};
+// Cellular/Wifi power monitor rail information
+static jmethodID jupdateRailData = NULL;
+static jmethodID jsetRailStatsAvailability = NULL;
+
+std::function<void(JNIEnv*, jobject)> gGetRailEnergyPowerStatsImpl = {};
+
+std::unordered_map<uint32_t, std::pair<std::string, std::string>> gPowerStatsHalRailNames = {};
+static bool power_monitor_available = false;
+
// The caller must be holding gPowerHalMutex.
static void deinitPowerStatsLocked() {
gPowerStatsHalV1_0 = nullptr;
@@ -258,6 +269,7 @@ static bool initializePowerStats() {
gPowerStatsHalStateNames.clear();
gPowerStatsHalPlatformIds.clear();
gPowerStatsHalSubsystemIds.clear();
+ gPowerStatsHalRailNames.clear();
Return<void> ret;
ret = gPowerStatsHalV1_0->getPowerEntityInfo([](auto infos, auto status) {
@@ -301,6 +313,27 @@ static bool initializePowerStats() {
return false;
}
+ // Get Power monitor rails available
+ ret = gPowerStatsHalV1_0->getRailInfo([](auto rails, auto status) {
+ if (status != Status::SUCCESS) {
+ ALOGW("Rail information is not available");
+ power_monitor_available = false;
+ return;
+ }
+
+ // Fill out rail names/subsystems into gPowerStatsHalRailNames
+ for (auto rail : rails) {
+ gPowerStatsHalRailNames.emplace(rail.index,
+ std::make_pair(rail.railName, rail.subsysName));
+ }
+ if (!gPowerStatsHalRailNames.empty()) {
+ power_monitor_available = true;
+ }
+ });
+ if (!checkResultLocked(ret, __func__)) {
+ return false;
+ }
+
return (!gPowerStatsHalEntityNames.empty()) && (!gPowerStatsHalStateNames.empty());
}
@@ -517,6 +550,50 @@ static jint getPowerStatsHalSubsystemData(JNIEnv* env, jobject outBuf) {
return total_added;
}
+static void getPowerStatsHalRailEnergyData(JNIEnv* env, jobject jrailStats) {
+ using android::hardware::power::stats::V1_0::Status;
+ using android::hardware::power::stats::V1_0::EnergyData;
+
+ if (!getPowerStatsHalLocked()) {
+ ALOGE("failed to get power stats");
+ return;
+ }
+
+ if (!power_monitor_available) {
+ env->CallVoidMethod(jrailStats, jsetRailStatsAvailability, false);
+ ALOGW("Rail energy data is not available");
+ return;
+ }
+
+ // Get power rail energySinceBoot data
+ Return<void> ret = gPowerStatsHalV1_0->getEnergyData({},
+ [&env, &jrailStats](auto energyData, auto status) {
+ if (status == Status::NOT_SUPPORTED) {
+ ALOGW("getEnergyData is not supported");
+ return;
+ }
+
+ for (auto data : energyData) {
+ if (!(data.timestamp > LLONG_MAX || data.energy > LLONG_MAX)) {
+ env->CallVoidMethod(jrailStats,
+ jupdateRailData,
+ data.index,
+ env->NewStringUTF(
+ gPowerStatsHalRailNames.at(data.index).first.c_str()),
+ env->NewStringUTF(
+ gPowerStatsHalRailNames.at(data.index).second.c_str()),
+ data.timestamp,
+ data.energy);
+ } else {
+ ALOGE("Java long overflow seen. Rail index %d not updated", data.index);
+ }
+ }
+ });
+ if (!checkResultLocked(ret, __func__)) {
+ ALOGE("getEnergyData failed");
+ }
+}
+
// The caller must be holding powerHalMutex.
static void getPowerHalLowPowerData(JNIEnv* env, jobject jrpmStats) {
sp<IPowerV1_0> powerHalV1_0 = getPowerHalV1_0();
@@ -761,11 +838,13 @@ static void setUpPowerStatsLocked() {
gGetLowPowerStatsImpl = getPowerStatsHalLowPowerData;
gGetPlatformLowPowerStatsImpl = getPowerStatsHalPlatformData;
gGetSubsystemLowPowerStatsImpl = getPowerStatsHalSubsystemData;
+ gGetRailEnergyPowerStatsImpl = getPowerStatsHalRailEnergyData;
} else if (android::hardware::power::V1_0::IPower::getService() != nullptr) {
ALOGI("Using power HAL");
gGetLowPowerStatsImpl = getPowerHalLowPowerData;
gGetPlatformLowPowerStatsImpl = getPowerHalPlatformData;
gGetSubsystemLowPowerStatsImpl = getPowerHalSubsystemData;
+ gGetRailEnergyPowerStatsImpl = NULL;
}
}
@@ -835,11 +914,44 @@ static jint getSubsystemLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject
return -1;
}
+static void getRailEnergyPowerStats(JNIEnv* env, jobject /* clazz */, jobject jrailStats) {
+ if (jrailStats == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException",
+ "The railstats jni input jobject jrailStats is null.");
+ return;
+ }
+ if (jupdateRailData == NULL) {
+ ALOGE("A railstats jni jmethodID is null.");
+ return;
+ }
+
+ std::lock_guard<std::mutex> lock(gPowerHalMutex);
+
+ if (!gGetRailEnergyPowerStatsImpl) {
+ setUpPowerStatsLocked();
+ }
+
+ if (gGetRailEnergyPowerStatsImpl) {
+ gGetRailEnergyPowerStatsImpl(env, jrailStats);
+ return;
+ }
+
+ if (jsetRailStatsAvailability == NULL) {
+ ALOGE("setRailStatsAvailability jni jmethodID is null.");
+ return;
+ }
+ env->CallVoidMethod(jrailStats, jsetRailStatsAvailability, false);
+ ALOGE("Unable to load Power.Stats.HAL. Setting rail availability to false");
+ return;
+}
+
static const JNINativeMethod method_table[] = {
{ "nativeWaitWakeup", "(Ljava/nio/ByteBuffer;)I", (void*)nativeWaitWakeup },
{ "getLowPowerStats", "(Lcom/android/internal/os/RpmStats;)V", (void*)getLowPowerStats },
{ "getPlatformLowPowerStats", "(Ljava/nio/ByteBuffer;)I", (void*)getPlatformLowPowerStats },
{ "getSubsystemLowPowerStats", "(Ljava/nio/ByteBuffer;)I", (void*)getSubsystemLowPowerStats },
+ { "getRailEnergyPowerStats", "(Lcom/android/internal/os/RailStats;)V",
+ (void*)getRailEnergyPowerStats },
};
int register_android_server_BatteryStatsService(JNIEnv *env)
@@ -850,8 +962,9 @@ int register_android_server_BatteryStatsService(JNIEnv *env)
env->FindClass("com/android/internal/os/RpmStats$PowerStatePlatformSleepState");
jclass clsPowerStateSubsystem =
env->FindClass("com/android/internal/os/RpmStats$PowerStateSubsystem");
+ jclass clsRailStats = env->FindClass("com/android/internal/os/RailStats");
if (clsRpmStats == NULL || clsPowerStatePlatformSleepState == NULL
- || clsPowerStateSubsystem == NULL) {
+ || clsPowerStateSubsystem == NULL || clsRailStats == NULL) {
ALOGE("A rpmstats jni jclass is null.");
} else {
jgetAndUpdatePlatformState = env->GetMethodID(clsRpmStats, "getAndUpdatePlatformState",
@@ -862,6 +975,10 @@ int register_android_server_BatteryStatsService(JNIEnv *env)
"(Ljava/lang/String;JI)V");
jputState = env->GetMethodID(clsPowerStateSubsystem, "putState",
"(Ljava/lang/String;JI)V");
+ jupdateRailData = env->GetMethodID(clsRailStats, "updateRailData",
+ "(JLjava/lang/String;Ljava/lang/String;JJ)V");
+ jsetRailStatsAvailability = env->GetMethodID(clsRailStats, "setRailStatsAvailability",
+ "(Z)V");
}
return jniRegisterNativeMethods(env, "com/android/server/am/BatteryStatsService",
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 33317b554988..57377c633c9a 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -249,7 +249,8 @@ public:
virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags);
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig);
virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags);
- virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags);
+ virtual void interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
+ uint32_t& policyFlags);
virtual nsecs_t interceptKeyBeforeDispatching(
const sp<IBinder>& token,
const KeyEvent* keyEvent, uint32_t policyFlags);
@@ -373,6 +374,9 @@ void NativeInputManager::dump(std::string& dump) {
mInputManager->getReader()->dump(dump);
dump += "\n";
+ mInputManager->getClassifier()->dump(dump);
+ dump += "\n";
+
mInputManager->getDispatcher()->dump(dump);
dump += "\n";
}
@@ -1063,7 +1067,8 @@ void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
}
}
-void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
+void NativeInputManager::interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
+ uint32_t& policyFlags) {
ATRACE_CALL();
// Policy:
// - Ignore untrusted events and pass them along.
@@ -1081,7 +1086,7 @@ void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& p
JNIEnv* env = jniEnv();
jint wmActions = env->CallIntMethod(mServiceObj,
gServiceClassInfo.interceptMotionBeforeQueueingNonInteractive,
- when, policyFlags);
+ displayId, when, policyFlags);
if (checkAndClearExceptionFromCallback(env,
"interceptMotionBeforeQueueingNonInteractive")) {
wmActions = 0;
@@ -1791,7 +1796,7 @@ int register_android_server_InputManager(JNIEnv* env) {
"interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;I)I");
GET_METHOD_ID(gServiceClassInfo.interceptMotionBeforeQueueingNonInteractive, clazz,
- "interceptMotionBeforeQueueingNonInteractive", "(JI)I");
+ "interceptMotionBeforeQueueingNonInteractive", "(IJI)I");
GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeDispatching, clazz,
"interceptKeyBeforeDispatching",
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index cbc3791264bf..d178c3abc906 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -973,7 +973,10 @@ void GnssMeasurementCallback::translateSingleGnssMeasurement
JavaObject& object) {
translateSingleGnssMeasurement(&(measurement_V2_0->v1_1), object);
- SET(CodeType, (static_cast<int32_t>(measurement_V2_0->codeType)));
+ SET(CodeType, static_cast<int32_t>(measurement_V2_0->codeType));
+
+ // Overwrite with v2_0.state since v2_0->v1_1->v1_0.state is deprecated.
+ SET(State, static_cast<int32_t>(measurement_V2_0->state));
}
jobject GnssMeasurementCallback::translateGnssClock(
diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/services/core/jni/com_android_server_security_VerityUtils.cpp
index bf96f9a3b71b..6cd9f2c718ee 100644
--- a/services/core/jni/com_android_server_security_VerityUtils.cpp
+++ b/services/core/jni/com_android_server_security_VerityUtils.cpp
@@ -122,7 +122,7 @@ class JavaByteArrayHolder {
}
~JavaByteArrayHolder() {
- LOG_ALWAYS_FATAL_IF(mElements == nullptr, "Elements are not released");
+ LOG_ALWAYS_FATAL_IF(mElements != nullptr, "Elements are not released");
}
private:
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java b/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java
index de5dd1749830..d5cfab960171 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java
@@ -16,7 +16,7 @@
package com.android.server.devicepolicy;
-import android.app.admin.DevicePolicyManager.InstallUpdateCallback;
+import android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback;
import android.app.admin.StartInstallingUpdateCallback;
import android.content.Context;
import android.os.ParcelFileDescriptor;
@@ -62,41 +62,43 @@ class AbUpdateInstaller extends UpdateInstaller {
private static Map<Integer, Integer> buildErrorCodesMap() {
Map<Integer, Integer> map = new HashMap<>();
- map.put(UpdateEngine.ErrorCodeConstants.ERROR, InstallUpdateCallback.UPDATE_ERROR_UNKNOWN);
+ map.put(
+ UpdateEngine.ErrorCodeConstants.ERROR,
+ InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
map.put(
DOWNLOAD_STATE_INITIALIZATION_ERROR,
- InstallUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION);
+ InstallSystemUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION);
map.put(
UpdateEngine.ErrorCodeConstants.PAYLOAD_TIMESTAMP_ERROR,
- InstallUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION);
+ InstallSystemUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION);
// Error constants corresponding to errors related to bad update file.
map.put(
UpdateEngine.ErrorCodeConstants.DOWNLOAD_PAYLOAD_VERIFICATION_ERROR,
- InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID);
+ InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID);
map.put(
UpdateEngine.ErrorCodeConstants.PAYLOAD_SIZE_MISMATCH_ERROR,
- InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID);
+ InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID);
map.put(
UpdateEngine.ErrorCodeConstants.PAYLOAD_MISMATCHED_TYPE_ERROR,
- InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID);
+ InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID);
map.put(
UpdateEngine.ErrorCodeConstants.PAYLOAD_HASH_MISMATCH_ERROR,
- InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID);
+ InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID);
// Error constants corresponding to errors related to devices bad state.
map.put(
UpdateEngine.ErrorCodeConstants.POST_INSTALL_RUNNER_ERROR,
- InstallUpdateCallback.UPDATE_ERROR_UNKNOWN);
+ InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
map.put(
UpdateEngine.ErrorCodeConstants.INSTALL_DEVICE_OPEN_ERROR,
- InstallUpdateCallback.UPDATE_ERROR_UNKNOWN);
+ InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
map.put(
UpdateEngine.ErrorCodeConstants.DOWNLOAD_TRANSFER_ERROR,
- InstallUpdateCallback.UPDATE_ERROR_UNKNOWN);
+ InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
map.put(
UpdateEngine.ErrorCodeConstants.UPDATED_BUT_NOT_ACTIVE,
- InstallUpdateCallback.UPDATE_ERROR_UNKNOWN);
+ InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
return map;
}
@@ -153,12 +155,13 @@ class AbUpdateInstaller extends UpdateInstaller {
} catch (ZipException e) {
Log.w(UpdateInstaller.TAG, e);
notifyCallbackOnError(
- InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID,
+ InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID,
Log.getStackTraceString(e));
} catch (IOException e) {
Log.w(UpdateInstaller.TAG, e);
notifyCallbackOnError(
- InstallUpdateCallback.UPDATE_ERROR_UNKNOWN, Log.getStackTraceString(e));
+ InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN,
+ Log.getStackTraceString(e));
}
}
@@ -185,7 +188,7 @@ class AbUpdateInstaller extends UpdateInstaller {
if (mSizeForUpdate == -1) {
Log.w(UpdateInstaller.TAG, "Failed to find payload entry in the given package.");
notifyCallbackOnError(
- InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID,
+ InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID,
"Failed to find payload entry in the given package.");
return;
}
@@ -210,7 +213,7 @@ class AbUpdateInstaller extends UpdateInstaller {
if (entry.getMethod() != ZipEntry.STORED) {
Log.w(UpdateInstaller.TAG, "Invalid compression method.");
notifyCallbackOnError(
- InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID,
+ InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID,
"Invalid compression method.");
return false;
}
@@ -263,7 +266,7 @@ class AbUpdateInstaller extends UpdateInstaller {
} else {
mUpdateInstaller.notifyCallbackOnError(
errorCodesMap.getOrDefault(
- errorCode, InstallUpdateCallback.UPDATE_ERROR_UNKNOWN),
+ errorCode, InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN),
errorStringsMap.getOrDefault(errorCode, UNKNOWN_ERROR + errorCode));
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1155f499d619..9523202cbb0e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -17,8 +17,8 @@
package com.android.server.devicepolicy;
import static android.Manifest.permission.BIND_DEVICE_ADMIN;
-import static android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY;
import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
+import static android.Manifest.permission.REQUEST_SCREEN_LOCK_COMPLEXITY;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
@@ -247,6 +247,7 @@ import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.pm.UserRestrictionsUtils;
import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
import com.google.android.collect.Sets;
@@ -1870,7 +1871,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Owners newOwners() {
return new Owners(getUserManager(), getUserManagerInternal(),
- getPackageManagerInternal());
+ getPackageManagerInternal(), getActivityTaskManagerInternal());
}
UserManager getUserManager() {
@@ -1885,6 +1886,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return LocalServices.getService(PackageManagerInternal.class);
}
+ ActivityTaskManagerInternal getActivityTaskManagerInternal() {
+ return LocalServices.getService(ActivityTaskManagerInternal.class);
+ }
+
UsageStatsManagerInternal getUsageStatsManagerInternal() {
return LocalServices.getService(UsageStatsManagerInternal.class);
}
@@ -4773,8 +4778,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final int callingUserId = mInjector.userHandleGetCallingUserId();
enforceUserUnlocked(callingUserId);
mContext.enforceCallingOrSelfPermission(
- GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY,
- "Must have " + GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY + " permission.");
+ REQUEST_SCREEN_LOCK_COMPLEXITY,
+ "Must have " + REQUEST_SCREEN_LOCK_COMPLEXITY + " permission.");
synchronized (getLockObject()) {
int targetUserId = getCredentialOwner(callingUserId, /* parent= */ false);
@@ -12790,10 +12795,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
- // TODO(b/22388012): When backup is available for secondary users and profiles, consider
- // whether there are any privacy/security implications of enabling the backup service here
- // if there are other users or profiles unmanaged or managed by a different entity (i.e. not
- // affiliated).
@Override
public void setBackupServiceEnabled(ComponentName admin, boolean enabled) {
if (!mHasFeature) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NonAbUpdateInstaller.java b/services/devicepolicy/java/com/android/server/devicepolicy/NonAbUpdateInstaller.java
index 5f1e92682ac1..582306c52806 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NonAbUpdateInstaller.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NonAbUpdateInstaller.java
@@ -16,7 +16,7 @@
package com.android.server.devicepolicy;
-import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback;
import android.app.admin.StartInstallingUpdateCallback;
import android.content.Context;
import android.os.ParcelFileDescriptor;
@@ -45,7 +45,7 @@ class NonAbUpdateInstaller extends UpdateInstaller {
} catch (IOException e) {
Log.w(TAG, "IO error while trying to install non AB update.", e);
notifyCallbackOnError(
- DevicePolicyManager.InstallUpdateCallback.UPDATE_ERROR_UNKNOWN,
+ InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN,
Log.getStackTraceString(e));
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index ee1c1df3f162..27cd70c9a606 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -41,6 +41,7 @@ import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
import com.android.server.LocalServices;
+import com.android.server.wm.ActivityTaskManagerInternal;
import libcore.io.IoUtils;
@@ -104,6 +105,7 @@ class Owners {
private final UserManager mUserManager;
private final UserManagerInternal mUserManagerInternal;
private final PackageManagerInternal mPackageManagerInternal;
+ private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
private boolean mSystemReady;
@@ -129,18 +131,22 @@ class Owners {
public Owners(UserManager userManager,
UserManagerInternal userManagerInternal,
- PackageManagerInternal packageManagerInternal) {
- this(userManager, userManagerInternal, packageManagerInternal, new Injector());
+ PackageManagerInternal packageManagerInternal,
+ ActivityTaskManagerInternal activityTaskManagerInternal) {
+ this(userManager, userManagerInternal, packageManagerInternal,
+ activityTaskManagerInternal, new Injector());
}
@VisibleForTesting
Owners(UserManager userManager,
UserManagerInternal userManagerInternal,
PackageManagerInternal packageManagerInternal,
+ ActivityTaskManagerInternal activityTaskManagerInternal,
Injector injector) {
mUserManager = userManager;
mUserManagerInternal = userManagerInternal;
mPackageManagerInternal = packageManagerInternal;
+ mActivityTaskManagerInternal = activityTaskManagerInternal;
mInjector = injector;
}
@@ -187,6 +193,7 @@ class Owners {
getDeviceOwnerUserId()));
}
pushToPackageManagerLocked();
+ pushToActivityTaskManagerLocked();
pushToAppOpsLocked();
}
}
@@ -201,6 +208,11 @@ class Owners {
po);
}
+ private void pushToActivityTaskManagerLocked() {
+ mActivityTaskManagerInternal.setDeviceOwnerPackageName(mDeviceOwner != null
+ ? mDeviceOwner.packageName : null);
+ }
+
String getDeviceOwnerPackageName() {
synchronized (mLock) {
return mDeviceOwner != null ? mDeviceOwner.packageName : null;
@@ -275,6 +287,7 @@ class Owners {
mUserManagerInternal.setDeviceManaged(true);
pushToPackageManagerLocked();
+ pushToActivityTaskManagerLocked();
pushToAppOpsLocked();
}
}
@@ -286,6 +299,7 @@ class Owners {
mUserManagerInternal.setDeviceManaged(false);
pushToPackageManagerLocked();
+ pushToActivityTaskManagerLocked();
pushToAppOpsLocked();
}
}
@@ -333,6 +347,7 @@ class Owners {
mDeviceOwner.remoteBugreportHash, /* canAccessDeviceIds =*/
mDeviceOwner.canAccessDeviceIds);
pushToPackageManagerLocked();
+ pushToActivityTaskManagerLocked();
pushToAppOpsLocked();
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java b/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java
index cf68ccf9f306..7148ed4523d1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java
@@ -18,7 +18,7 @@ package com.android.server.devicepolicy;
import android.annotation.Nullable;
import android.app.admin.DevicePolicyEventLogger;
-import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback;
import android.app.admin.StartInstallingUpdateCallback;
import android.content.Context;
import android.content.Intent;
@@ -66,7 +66,7 @@ abstract class UpdateInstaller {
mCopiedUpdateFile = null;
if (!isBatteryLevelSufficient()) {
notifyCallbackOnError(
- DevicePolicyManager.InstallUpdateCallback.UPDATE_ERROR_BATTERY_LOW,
+ InstallSystemUpdateCallback.UPDATE_ERROR_BATTERY_LOW,
"The battery level must be above "
+ mConstants.BATTERY_THRESHOLD_NOT_CHARGING + " while not charging or"
+ "above " + mConstants.BATTERY_THRESHOLD_CHARGING + " while charging");
@@ -76,7 +76,7 @@ abstract class UpdateInstaller {
mCopiedUpdateFile = copyUpdateFileToDataOtaPackageDir();
if (mCopiedUpdateFile == null) {
notifyCallbackOnError(
- DevicePolicyManager.InstallUpdateCallback.UPDATE_ERROR_UNKNOWN,
+ InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN,
"Error while copying file.");
return;
}
@@ -111,7 +111,7 @@ abstract class UpdateInstaller {
} catch (IOException e) {
Log.w(TAG, "Failed to copy update file to OTA directory", e);
notifyCallbackOnError(
- DevicePolicyManager.InstallUpdateCallback.UPDATE_ERROR_UNKNOWN,
+ InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN,
Log.getStackTraceString(e));
return null;
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ab30cda271f0..a6017f2c1e86 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -64,6 +64,7 @@ import android.util.EventLog;
import android.util.Slog;
import android.util.TimingsTraceLog;
import android.view.WindowManager;
+import android.view.contentcapture.ContentCaptureManager;
import android.view.inputmethod.InputMethodSystemProperty;
import com.android.internal.R;
@@ -2214,33 +2215,30 @@ public final class SystemServer {
}
private void startContentCaptureService(@NonNull Context context) {
- // Check if it was explicitly enabled by DeviceConfig
- final String settings = DeviceConfig.getProperty(DeviceConfig.ContentCapture.NAMESPACE,
- DeviceConfig.ContentCapture.PROPERTY_CONTENTCAPTURE_ENABLED);
- if (settings == null) {
- // Better be safe than sorry...
- Slog.d(TAG, "ContentCaptureService disabled because its not set by OEM");
- return;
- }
- switch (settings) {
- case "always":
- // Should be used only during development
+ // First check if it was explicitly enabled by DeviceConfig
+ boolean explicitlySupported = false;
+ String settings = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED);
+ if (settings != null && !settings.equalsIgnoreCase("default")) {
+ explicitlySupported = Boolean.parseBoolean(settings);
+ if (explicitlySupported) {
Slog.d(TAG, "ContentCaptureService explicitly enabled by DeviceConfig");
- break;
- case "default":
- // Default case: check if OEM overlaid the resource that defines the service.
- final String serviceName = context.getString(
- com.android.internal.R.string.config_defaultContentCaptureService);
- if (TextUtils.isEmpty(serviceName)) {
- Slog.d(TAG, "ContentCaptureService disabled because resource is not overlaid");
- return;
- }
- break;
- default:
- // Kill switch for OEMs
- Slog.d(TAG, "ContentCaptureService disabled because its set to: " + settings);
+ } else {
+ Slog.d(TAG, "ContentCaptureService explicitly disabled by DeviceConfig");
return;
+ }
}
+
+ // Then check if OEM overlaid the resource that defines the service.
+ if (!explicitlySupported) {
+ final String serviceName = context
+ .getString(com.android.internal.R.string.config_defaultContentCaptureService);
+ if (TextUtils.isEmpty(serviceName)) {
+ Slog.d(TAG, "ContentCaptureService disabled because resource is not overlaid");
+ return;
+ }
+ }
+
traceBeginAndSlog("StartContentCaptureService");
mSystemServiceManager.startService(CONTENT_CAPTURE_MANAGER_SERVICE_CLASS);
traceEnd();
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 638ec95ec544..9946cc3db0e8 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -1,6 +1,9 @@
java_library_static {
name: "services.net",
srcs: ["java/**/*.java"],
+ static_libs: [
+ "netd_aidl_interface-java",
+ ]
}
filegroup {
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingMapTest.java
index 4354db72554a..24e5573b891d 100644
--- a/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingMapTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -11,7 +11,7 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
package com.android.server.backup.encryption.chunk;
@@ -36,7 +36,7 @@ import java.util.Arrays;
@RunWith(RobolectricTestRunner.class)
@Presubmit
-public class ChunkListingTest {
+public class ChunkListingMapTest {
private static final String CHUNK_A = "CHUNK_A";
private static final String CHUNK_B = "CHUNK_B";
private static final String CHUNK_C = "CHUNK_C";
@@ -62,13 +62,13 @@ public class ChunkListingTest {
createChunkListingProto(
new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC},
new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH});
- ChunkListing chunkListing =
- ChunkListing.readFromProto(
+ ChunkListingMap chunkListingMap =
+ ChunkListingMap.readFromProto(
new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
- boolean chunkAInList = chunkListing.hasChunk(mChunkHashA);
- boolean chunkBInList = chunkListing.hasChunk(mChunkHashB);
- boolean chunkCInList = chunkListing.hasChunk(mChunkHashC);
+ boolean chunkAInList = chunkListingMap.hasChunk(mChunkHashA);
+ boolean chunkBInList = chunkListingMap.hasChunk(mChunkHashB);
+ boolean chunkCInList = chunkListingMap.hasChunk(mChunkHashC);
assertThat(chunkAInList).isTrue();
assertThat(chunkBInList).isTrue();
@@ -81,13 +81,13 @@ public class ChunkListingTest {
createChunkListingProto(
new ChunkHash[] {mChunkHashA, mChunkHashB},
new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH});
- ChunkListing chunkListing =
- ChunkListing.readFromProto(
+ ChunkListingMap chunkListingMap =
+ ChunkListingMap.readFromProto(
new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
ChunkHash chunkHashEmpty = getHash("");
- boolean chunkCInList = chunkListing.hasChunk(mChunkHashC);
- boolean emptyChunkInList = chunkListing.hasChunk(chunkHashEmpty);
+ boolean chunkCInList = chunkListingMap.hasChunk(mChunkHashC);
+ boolean emptyChunkInList = chunkListingMap.hasChunk(chunkHashEmpty);
assertThat(chunkCInList).isFalse();
assertThat(emptyChunkInList).isFalse();
@@ -99,13 +99,13 @@ public class ChunkListingTest {
createChunkListingProto(
new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC},
new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH});
- ChunkListing chunkListing =
- ChunkListing.readFromProto(
+ ChunkListingMap chunkListingMap =
+ ChunkListingMap.readFromProto(
new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
- ChunkListing.Entry entryA = chunkListing.getChunkEntry(mChunkHashA);
- ChunkListing.Entry entryB = chunkListing.getChunkEntry(mChunkHashB);
- ChunkListing.Entry entryC = chunkListing.getChunkEntry(mChunkHashC);
+ ChunkListingMap.Entry entryA = chunkListingMap.getChunkEntry(mChunkHashA);
+ ChunkListingMap.Entry entryB = chunkListingMap.getChunkEntry(mChunkHashB);
+ ChunkListingMap.Entry entryC = chunkListingMap.getChunkEntry(mChunkHashC);
assertThat(entryA.getLength()).isEqualTo(CHUNK_A_LENGTH);
assertThat(entryB.getLength()).isEqualTo(CHUNK_B_LENGTH);
@@ -118,13 +118,13 @@ public class ChunkListingTest {
createChunkListingProto(
new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC},
new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH});
- ChunkListing chunkListing =
- ChunkListing.readFromProto(
+ ChunkListingMap chunkListingMap =
+ ChunkListingMap.readFromProto(
new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
- ChunkListing.Entry entryA = chunkListing.getChunkEntry(mChunkHashA);
- ChunkListing.Entry entryB = chunkListing.getChunkEntry(mChunkHashB);
- ChunkListing.Entry entryC = chunkListing.getChunkEntry(mChunkHashC);
+ ChunkListingMap.Entry entryA = chunkListingMap.getChunkEntry(mChunkHashA);
+ ChunkListingMap.Entry entryB = chunkListingMap.getChunkEntry(mChunkHashB);
+ ChunkListingMap.Entry entryC = chunkListingMap.getChunkEntry(mChunkHashC);
assertThat(entryA.getStart()).isEqualTo(0);
assertThat(entryB.getStart()).isEqualTo(CHUNK_A_LENGTH);
@@ -137,22 +137,24 @@ public class ChunkListingTest {
createChunkListingProto(
new ChunkHash[] {mChunkHashA, mChunkHashB},
new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH});
- ChunkListing chunkListing =
- ChunkListing.readFromProto(
+ ChunkListingMap chunkListingMap =
+ ChunkListingMap.readFromProto(
new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
- ChunkListing.Entry chunkEntryNonexistentChunk = chunkListing.getChunkEntry(mChunkHashC);
+ ChunkListingMap.Entry chunkEntryNonexistentChunk =
+ chunkListingMap.getChunkEntry(mChunkHashC);
assertThat(chunkEntryNonexistentChunk).isNull();
}
@Test
- public void testReadFromProto_whenEmptyProto_returnsChunkListingWith0Chunks() throws Exception {
+ public void testReadFromProto_whenEmptyProto_returnsChunkListingMapWith0Chunks()
+ throws Exception {
ProtoInputStream emptyProto = new ProtoInputStream(new ByteArrayInputStream(new byte[] {}));
- ChunkListing chunkListing = ChunkListing.readFromProto(emptyProto);
+ ChunkListingMap chunkListingMap = ChunkListingMap.readFromProto(emptyProto);
- assertThat(chunkListing.getChunkCount()).isEqualTo(0);
+ assertThat(chunkListingMap.getChunkCount()).isEqualTo(0);
}
@Test
@@ -162,11 +164,11 @@ public class ChunkListingTest {
new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC},
new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH});
- ChunkListing chunkListing =
- ChunkListing.readFromProto(
+ ChunkListingMap chunkListingMap =
+ ChunkListingMap.readFromProto(
new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
- assertThat(chunkListing.getChunkCount()).isEqualTo(3);
+ assertThat(chunkListingMap.getChunkCount()).isEqualTo(3);
}
private byte[] createChunkListingProto(ChunkHash[] hashes, int[] lengths) {
diff --git a/services/robotests/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java
index 8df08262c9fa..8df08262c9fa 100644
--- a/services/robotests/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java
diff --git a/services/robotests/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java
index 2af6f2bee8ff..2af6f2bee8ff 100644
--- a/services/robotests/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java
diff --git a/services/robotests/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java
index 73baf80a2c70..73baf80a2c70 100644
--- a/services/robotests/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index 53d72bb9a415..e51ee947cba1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -19,6 +19,7 @@ import static androidx.test.InstrumentationRegistry.getContext;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -51,6 +52,9 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
@@ -82,6 +86,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
@@ -105,6 +110,8 @@ public class DeviceIdleControllerTest {
@Mock
private ContentResolver mContentResolver;
@Mock
+ private DeviceIdleController.MyHandler mHandler;
+ @Mock
private IActivityManager mIActivityManager;
@Mock
private LocationManager mLocationManager;
@@ -154,7 +161,7 @@ public class DeviceIdleControllerTest {
@Override
DeviceIdleController.MyHandler getHandler(DeviceIdleController controller) {
- return mock(DeviceIdleController.MyHandler.class, Answers.RETURNS_DEEP_STUBS);
+ return mHandler;
}
@Override
@@ -232,10 +239,12 @@ public class DeviceIdleControllerTest {
.when(() -> LocalServices.getService(ActivityManagerInternal.class));
doReturn(mock(ActivityTaskManagerInternal.class))
.when(() -> LocalServices.getService(ActivityTaskManagerInternal.class));
+ doReturn(mock(AlarmManagerInternal.class))
+ .when(() -> LocalServices.getService(AlarmManagerInternal.class));
doReturn(mPowerManagerInternal)
.when(() -> LocalServices.getService(PowerManagerInternal.class));
- when(mPowerManagerInternal.getLowPowerState(anyInt())).thenReturn(
- mock(PowerSaveState.class));
+ when(mPowerManagerInternal.getLowPowerState(anyInt()))
+ .thenReturn(mock(PowerSaveState.class));
doReturn(mock(NetworkPolicyManagerInternal.class))
.when(() -> LocalServices.getService(NetworkPolicyManagerInternal.class));
when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(mWakeLock);
@@ -246,8 +255,11 @@ public class DeviceIdleControllerTest {
doReturn(true).when(mSensorManager).registerListener(any(), any(), anyInt());
mAppStateTracker = new AppStateTrackerForTest(getContext(), Looper.getMainLooper());
mAnyMotionDetector = new AnyMotionDetectorForTest();
+ mHandler = mock(DeviceIdleController.MyHandler.class, Answers.RETURNS_DEEP_STUBS);
+ doNothing().when(mHandler).handleMessage(any());
mInjector = new InjectorForTest(getContext());
doNothing().when(mContentResolver).registerContentObserver(any(), anyBoolean(), any());
+
mDeviceIdleController = new DeviceIdleController(getContext(), mInjector);
spyOn(mDeviceIdleController);
doNothing().when(mDeviceIdleController).publishBinderService(any(), any());
@@ -423,6 +435,29 @@ public class DeviceIdleControllerTest {
mDeviceIdleController.becomeInactiveIfAppropriateLocked();
verifyStateConditions(STATE_ACTIVE);
+
+ mConstants.WAIT_FOR_UNLOCK = false;
+ setScreenLocked(true);
+ setScreenOn(true);
+ setChargingOn(false);
+
+ mDeviceIdleController.becomeInactiveIfAppropriateLocked();
+ verifyStateConditions(STATE_ACTIVE);
+
+ setScreenLocked(false);
+ setScreenOn(true);
+ setChargingOn(false);
+
+ mDeviceIdleController.becomeInactiveIfAppropriateLocked();
+ verifyStateConditions(STATE_ACTIVE);
+
+ mConstants.WAIT_FOR_UNLOCK = true;
+ setScreenLocked(false);
+ setScreenOn(true);
+ setChargingOn(false);
+
+ mDeviceIdleController.becomeInactiveIfAppropriateLocked();
+ verifyStateConditions(STATE_ACTIVE);
}
@Test
@@ -1307,7 +1342,7 @@ public class DeviceIdleControllerTest {
}
@Test
- public void testbecomeActiveLocked_deep() {
+ public void testBecomeActiveLocked_deep() {
// becomeActiveLocked should put everything into ACTIVE.
enterDeepState(STATE_ACTIVE);
@@ -1344,7 +1379,7 @@ public class DeviceIdleControllerTest {
}
@Test
- public void testbecomeActiveLocked_light() {
+ public void testBecomeActiveLocked_light() {
// becomeActiveLocked should put everything into ACTIVE.
enterLightState(LIGHT_STATE_ACTIVE);
@@ -1376,6 +1411,163 @@ public class DeviceIdleControllerTest {
verifyLightStateConditions(LIGHT_STATE_ACTIVE);
}
+ /** Test based on b/119058625. */
+ @Test
+ public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOn_ScreenThenMotion() {
+ mConstants.WAIT_FOR_UNLOCK = true;
+ enterDeepState(STATE_IDLE);
+ reset(mAlarmManager);
+ spyOn(mDeviceIdleController);
+
+ mDeviceIdleController.keyguardShowingLocked(true);
+ setScreenOn(true);
+ // With WAIT_FOR_UNLOCK = true and the screen locked, turning the screen on by itself
+ // shouldn't bring the device out of deep IDLE.
+ verifyStateConditions(STATE_IDLE);
+ mDeviceIdleController.handleMotionDetectedLocked(1000, "test");
+ // Motion should bring the device out of Doze. Since the screen is still locked (albeit
+ // on), the states should go back into INACTIVE.
+ verifyStateConditions(STATE_INACTIVE);
+ verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+ verify(mAlarmManager).cancel(eq(mDeviceIdleController.mDeepAlarmListener));
+ verify(mDeviceIdleController).scheduleReportActiveLocked(anyString(), anyInt());
+ }
+
+ /** Test based on b/119058625. */
+ @Test
+ public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOff_ScreenThenMotion() {
+ mConstants.WAIT_FOR_UNLOCK = true;
+ enterDeepState(STATE_IDLE);
+ reset(mAlarmManager);
+ spyOn(mDeviceIdleController);
+
+ mDeviceIdleController.keyguardShowingLocked(false);
+ setScreenOn(true);
+ // With WAIT_FOR_UNLOCK = true and the screen unlocked, turning the screen on by itself
+ // should bring the device out of deep IDLE.
+ verifyStateConditions(STATE_ACTIVE);
+ verifyLightStateConditions(LIGHT_STATE_ACTIVE);
+ verify(mAlarmManager).cancel(eq(mDeviceIdleController.mDeepAlarmListener));
+ verify(mDeviceIdleController).scheduleReportActiveLocked(anyString(), anyInt());
+ }
+
+ /** Test based on b/119058625. */
+ @Test
+ public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOn_MotionThenScreen() {
+ mConstants.WAIT_FOR_UNLOCK = true;
+ enterDeepState(STATE_IDLE);
+ reset(mAlarmManager);
+ spyOn(mDeviceIdleController);
+
+ InOrder alarmManagerInOrder = inOrder(mAlarmManager);
+ InOrder controllerInOrder = inOrder(mDeviceIdleController);
+
+ mDeviceIdleController.keyguardShowingLocked(true);
+ mDeviceIdleController.handleMotionDetectedLocked(1000, "test");
+ // The screen is still off, so motion should result in the INACTIVE state.
+ verifyStateConditions(STATE_INACTIVE);
+ verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+ alarmManagerInOrder.verify(mAlarmManager)
+ .cancel(eq(mDeviceIdleController.mDeepAlarmListener));
+ controllerInOrder.verify(mDeviceIdleController)
+ .scheduleReportActiveLocked(anyString(), anyInt());
+
+ setScreenOn(true);
+ // With WAIT_FOR_UNLOCK = true and the screen locked, turning the screen on by itself
+ // shouldn't bring the device all the way to ACTIVE.
+ verifyStateConditions(STATE_INACTIVE);
+ verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+ alarmManagerInOrder.verify(mAlarmManager, never()).cancel(
+ eq(mDeviceIdleController.mDeepAlarmListener));
+
+ // User finally unlocks the device. Device should be fully active.
+ mDeviceIdleController.keyguardShowingLocked(false);
+ verifyStateConditions(STATE_ACTIVE);
+ verifyLightStateConditions(LIGHT_STATE_ACTIVE);
+ alarmManagerInOrder.verify(mAlarmManager)
+ .cancel(eq(mDeviceIdleController.mDeepAlarmListener));
+ controllerInOrder.verify(mDeviceIdleController)
+ .scheduleReportActiveLocked(anyString(), anyInt());
+ }
+
+ /** Test based on b/119058625. */
+ @Test
+ public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOff_MotionThenScreen() {
+ mConstants.WAIT_FOR_UNLOCK = true;
+ enterDeepState(STATE_IDLE);
+ reset(mAlarmManager);
+ spyOn(mDeviceIdleController);
+
+ InOrder alarmManagerInOrder = inOrder(mAlarmManager);
+ InOrder controllerInOrder = inOrder(mDeviceIdleController);
+
+ mDeviceIdleController.keyguardShowingLocked(false);
+ mDeviceIdleController.handleMotionDetectedLocked(1000, "test");
+ // The screen is still off, so motion should result in the INACTIVE state.
+ verifyStateConditions(STATE_INACTIVE);
+ verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+ alarmManagerInOrder.verify(mAlarmManager)
+ .cancel(eq(mDeviceIdleController.mDeepAlarmListener));
+ controllerInOrder.verify(mDeviceIdleController)
+ .scheduleReportActiveLocked(anyString(), anyInt());
+
+ setScreenOn(true);
+ // With WAIT_FOR_UNLOCK = true and the screen unlocked, turning the screen on by itself
+ // should bring the device out of deep IDLE.
+ verifyStateConditions(STATE_ACTIVE);
+ verifyLightStateConditions(LIGHT_STATE_ACTIVE);
+ alarmManagerInOrder.verify(mAlarmManager)
+ .cancel(eq(mDeviceIdleController.mDeepAlarmListener));
+ controllerInOrder.verify(mDeviceIdleController)
+ .scheduleReportActiveLocked(anyString(), anyInt());
+ }
+
+ @Test
+ public void testExitNotifiesDependencies_WaitForUnlockOff_Screen() {
+ mConstants.WAIT_FOR_UNLOCK = false;
+ enterDeepState(STATE_IDLE);
+ reset(mAlarmManager);
+ spyOn(mDeviceIdleController);
+
+ setScreenOn(true);
+ // With WAIT_FOR_UNLOCK = false and the screen locked, turning the screen on by itself
+ // should bring the device out of deep IDLE.
+ verifyStateConditions(STATE_ACTIVE);
+ verifyLightStateConditions(LIGHT_STATE_ACTIVE);
+ verify(mAlarmManager).cancel(eq(mDeviceIdleController.mDeepAlarmListener));
+ verify(mDeviceIdleController).scheduleReportActiveLocked(anyString(), anyInt());
+ }
+
+ @Test
+ public void testExitNotifiesDependencies_WaitForUnlockOff_MotionThenScreen() {
+ mConstants.WAIT_FOR_UNLOCK = false;
+ enterDeepState(STATE_IDLE);
+ reset(mAlarmManager);
+ spyOn(mDeviceIdleController);
+
+ InOrder alarmManagerInOrder = inOrder(mAlarmManager);
+ InOrder controllerInOrder = inOrder(mDeviceIdleController);
+
+ mDeviceIdleController.handleMotionDetectedLocked(1000, "test");
+ // The screen is still off, so motion should result in the INACTIVE state.
+ verifyStateConditions(STATE_INACTIVE);
+ verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+ alarmManagerInOrder.verify(mAlarmManager)
+ .cancel(eq(mDeviceIdleController.mDeepAlarmListener));
+ controllerInOrder.verify(mDeviceIdleController)
+ .scheduleReportActiveLocked(anyString(), anyInt());
+
+ setScreenOn(true);
+ // With WAIT_FOR_UNLOCK = false and the screen locked, turning the screen on by itself
+ // should bring the device out of deep IDLE.
+ verifyStateConditions(STATE_ACTIVE);
+ verifyLightStateConditions(LIGHT_STATE_ACTIVE);
+ alarmManagerInOrder.verify(mAlarmManager)
+ .cancel(eq(mDeviceIdleController.mDeepAlarmListener));
+ controllerInOrder.verify(mDeviceIdleController)
+ .scheduleReportActiveLocked(anyString(), anyInt());
+ }
+
@Test
public void testStepToIdleMode() {
float delta = mDeviceIdleController.MIN_PRE_IDLE_FACTOR_CHANGE;
@@ -1508,6 +1700,10 @@ public class DeviceIdleControllerTest {
mDeviceIdleController.updateChargingLocked(on);
}
+ private void setScreenLocked(boolean locked) {
+ mDeviceIdleController.keyguardShowingLocked(locked);
+ }
+
private void setScreenOn(boolean on) {
doReturn(on).when(mPowerManager).isInteractive();
mDeviceIdleController.updateInteractivityLocked();
@@ -1549,7 +1745,8 @@ public class DeviceIdleControllerTest {
assertFalse(mDeviceIdleController.mMotionListener.isActive());
assertFalse(mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
- assertFalse(mDeviceIdleController.isScreenOn());
+ assertFalse(mDeviceIdleController.isScreenOn()
+ && !mDeviceIdleController.isKeyguardShowing());
break;
case STATE_IDLE_PENDING:
assertEquals(
@@ -1557,7 +1754,8 @@ public class DeviceIdleControllerTest {
mDeviceIdleController.mMotionListener.isActive());
assertFalse(mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
- assertFalse(mDeviceIdleController.isScreenOn());
+ assertFalse(mDeviceIdleController.isScreenOn()
+ && !mDeviceIdleController.isKeyguardShowing());
break;
case STATE_SENSING:
assertEquals(
@@ -1567,14 +1765,16 @@ public class DeviceIdleControllerTest {
mDeviceIdleController.hasMotionSensor(),
mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
- assertFalse(mDeviceIdleController.isScreenOn());
+ assertFalse(mDeviceIdleController.isScreenOn()
+ && !mDeviceIdleController.isKeyguardShowing());
break;
case STATE_LOCATING:
assertEquals(
mDeviceIdleController.hasMotionSensor(),
mDeviceIdleController.mMotionListener.isActive());
assertFalse(mDeviceIdleController.isCharging());
- assertFalse(mDeviceIdleController.isScreenOn());
+ assertFalse(mDeviceIdleController.isScreenOn()
+ && !mDeviceIdleController.isKeyguardShowing());
break;
case STATE_IDLE:
if (mDeviceIdleController.hasMotionSensor()) {
@@ -1584,7 +1784,8 @@ public class DeviceIdleControllerTest {
}
assertFalse(mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
- assertFalse(mDeviceIdleController.isScreenOn());
+ assertFalse(mDeviceIdleController.isScreenOn()
+ && !mDeviceIdleController.isKeyguardShowing());
// Light state should be OVERRIDE at this point.
verifyLightStateConditions(LIGHT_STATE_OVERRIDE);
break;
@@ -1596,14 +1797,16 @@ public class DeviceIdleControllerTest {
}
assertFalse(mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
- assertFalse(mDeviceIdleController.isScreenOn());
+ assertFalse(mDeviceIdleController.isScreenOn()
+ && !mDeviceIdleController.isKeyguardShowing());
break;
case STATE_QUICK_DOZE_DELAY:
// If quick doze is enabled, the motion listener should NOT be active.
assertFalse(mDeviceIdleController.mMotionListener.isActive());
assertFalse(mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
- assertFalse(mDeviceIdleController.isScreenOn());
+ assertFalse(mDeviceIdleController.isScreenOn()
+ && !mDeviceIdleController.isKeyguardShowing());
break;
default:
fail("Conditions for " + stateToString(expectedState) + " unknown.");
@@ -1632,7 +1835,8 @@ public class DeviceIdleControllerTest {
case LIGHT_STATE_IDLE_MAINTENANCE:
case LIGHT_STATE_OVERRIDE:
assertFalse(mDeviceIdleController.isCharging());
- assertFalse(mDeviceIdleController.isScreenOn());
+ assertFalse(mDeviceIdleController.isScreenOn()
+ && !mDeviceIdleController.isKeyguardShowing());
break;
default:
fail("Conditions for " + lightStateToString(expectedLightState) + " unknown.");
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index dc31c0f7ebbb..fce7599d0b59 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -66,6 +66,8 @@
<uses-permission android:name="android.permission.CONTROL_KEYGUARD"/>
<uses-permission android:name="android.permission.MANAGE_BIND_INSTANT_SERVICE"/>
<uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
+ <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
<!-- Uses API introduced in O (26) -->
<uses-sdk android:minSdkVersion="1"
diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementInternalTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementInternalTest.java
index 4bac200a22c6..ebbebcb02923 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkManagementInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkManagementInternalTest.java
@@ -16,12 +16,12 @@
package com.android.server;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
+import static android.net.INetd.FIREWALL_CHAIN_DOZABLE;
+import static android.net.INetd.FIREWALL_CHAIN_POWERSAVE;
+import static android.net.INetd.FIREWALL_CHAIN_STANDBY;
+import static android.net.INetd.FIREWALL_RULE_ALLOW;
+import static android.net.INetd.FIREWALL_RULE_DENY;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
import static android.util.DebugUtils.valueToString;
import static org.junit.Assert.assertEquals;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index a847b6ab105c..2ce4c54a932b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -65,7 +65,8 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
public OwnersTestable(MockSystemServices services) {
super(services.userManager, services.userManagerInternal,
- services.packageManagerInternal, new MockInjector(services));
+ services.packageManagerInternal, services.activityTaskManagerInternal,
+ new MockInjector(services));
}
static class MockInjector extends Injector {
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 9ac91ddba5ec..de782a52eb53 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -5199,7 +5199,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
public void testGetPasswordComplexity_currentUserNoPassword() {
when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE))
.thenReturn(true);
- mServiceContext.permissions.add(permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+ mServiceContext.permissions.add(permission.REQUEST_SCREEN_LOCK_COMPLEXITY);
when(getServices().userManager.getCredentialOwnerProfile(DpmMockContext.CALLER_USER_HANDLE))
.thenReturn(DpmMockContext.CALLER_USER_HANDLE);
@@ -5209,7 +5209,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
public void testGetPasswordComplexity_currentUserHasPassword() {
when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE))
.thenReturn(true);
- mServiceContext.permissions.add(permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+ mServiceContext.permissions.add(permission.REQUEST_SCREEN_LOCK_COMPLEXITY);
when(getServices().userManager.getCredentialOwnerProfile(DpmMockContext.CALLER_USER_HANDLE))
.thenReturn(DpmMockContext.CALLER_USER_HANDLE);
dpms.mUserPasswordMetrics.put(
@@ -5222,7 +5222,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
public void testGetPasswordComplexity_unifiedChallengeReturnsParentUserPassword() {
when(getServices().userManager.isUserUnlocked(DpmMockContext.CALLER_USER_HANDLE))
.thenReturn(true);
- mServiceContext.permissions.add(permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+ mServiceContext.permissions.add(permission.REQUEST_SCREEN_LOCK_COMPLEXITY);
UserInfo parentUser = new UserInfo();
parentUser.id = DpmMockContext.CALLER_USER_HANDLE + 10;
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 4724f1cdd324..8f0aeea3dbf8 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -64,6 +64,7 @@ import android.view.IWindowManager;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.net.NetworkPolicyManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.File;
import java.io.IOException;
@@ -94,6 +95,7 @@ public class MockSystemServices {
public final IActivityManager iactivityManager;
public final IActivityTaskManager iactivityTaskManager;
public ActivityManagerInternal activityManagerInternal;
+ public ActivityTaskManagerInternal activityTaskManagerInternal;
public final IPackageManager ipackageManager;
public final IBackupManager ibackupManager;
public final IAudioService iaudioService;
@@ -133,6 +135,7 @@ public class MockSystemServices {
iactivityManager = mock(IActivityManager.class);
iactivityTaskManager = mock(IActivityTaskManager.class);
activityManagerInternal = mock(ActivityManagerInternal.class);
+ activityTaskManagerInternal = mock(ActivityTaskManagerInternal.class);
ipackageManager = mock(IPackageManager.class);
ibackupManager = mock(IBackupManager.class);
iaudioService = mock(IAudioService.class);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
index 13436e7f8674..821d97acc230 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
@@ -24,14 +24,21 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static org.testng.Assert.expectThrows;
import android.app.KeyguardManager;
import android.content.Context;
+import android.os.RemoteException;
+import android.security.GateKeeper;
+import android.security.keystore.AndroidKeyStoreSecretKey;
+import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
+import android.service.gatekeeper.IGateKeeperService;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -53,6 +60,8 @@ import java.security.KeyStore;
import java.security.UnrecoverableKeyException;
import java.util.List;
+import javax.crypto.KeyGenerator;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class PlatformKeyManagerTest {
@@ -60,10 +69,15 @@ public class PlatformKeyManagerTest {
private static final String DATABASE_FILE_NAME = "recoverablekeystore.db";
private static final int USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS = 15;
private static final int USER_ID_FIXTURE = 42;
+ private static final long USER_SID = 4200L;
+ private static final String KEY_ALGORITHM = "AES";
+ private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
+ private static final String TESTING_KEYSTORE_KEY_ALIAS = "testing-key-store-key-alias";
@Mock private Context mContext;
@Mock private KeyStoreProxy mKeyStoreProxy;
@Mock private KeyguardManager mKeyguardManager;
+ @Mock private IGateKeeperService mGateKeeperService;
@Captor private ArgumentCaptor<KeyStore.ProtectionParameter> mProtectionParameterCaptor;
@Captor private ArgumentCaptor<KeyStore.Entry> mEntryArgumentCaptor;
@@ -74,18 +88,19 @@ public class PlatformKeyManagerTest {
private PlatformKeyManager mPlatformKeyManager;
@Before
- public void setUp() {
+ public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
Context context = InstrumentationRegistry.getTargetContext();
mDatabaseFile = context.getDatabasePath(DATABASE_FILE_NAME);
mRecoverableKeyStoreDb = RecoverableKeyStoreDb.newInstance(context);
- mPlatformKeyManager = new PlatformKeyManager(
- mContext, mKeyStoreProxy, mRecoverableKeyStoreDb);
+ mPlatformKeyManager = new PlatformKeyManagerTestable(
+ mContext, mKeyStoreProxy, mRecoverableKeyStoreDb, mGateKeeperService);
when(mContext.getSystemService(anyString())).thenReturn(mKeyguardManager);
when(mContext.getSystemServiceName(any())).thenReturn("test");
when(mKeyguardManager.isDeviceSecure(USER_ID_FIXTURE)).thenReturn(true);
+ when(mGateKeeperService.getSecureUserId(USER_ID_FIXTURE)).thenReturn(USER_SID);
}
@After
@@ -192,11 +207,36 @@ public class PlatformKeyManagerTest {
mPlatformKeyManager.init(USER_ID_FIXTURE);
assertEquals(
- USER_ID_FIXTURE,
+ USER_SID,
getDecryptKeyProtection().getBoundToSpecificSecureUserId());
}
@Test
+ public void init_doesNotCreateDecryptKeyIfNoSid() throws Exception {
+ when(mGateKeeperService.getSecureUserId(USER_ID_FIXTURE))
+ .thenReturn(GateKeeper.INVALID_SECURE_USER_ID);
+
+ mPlatformKeyManager.init(USER_ID_FIXTURE);
+
+ verify(mKeyStoreProxy, never()).setEntry(
+ eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"),
+ any(),
+ any());
+ }
+
+ @Test
+ public void init_doesNotCreateDecryptKeyOnGateKeeperException() throws Exception {
+ when(mGateKeeperService.getSecureUserId(USER_ID_FIXTURE)).thenThrow(new RemoteException());
+
+ expectThrows(RemoteException.class, () -> mPlatformKeyManager.init(USER_ID_FIXTURE));
+
+ verify(mKeyStoreProxy, never()).setEntry(
+ eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"),
+ any(),
+ any());
+ }
+
+ @Test
public void init_createsBothKeysWithSameMaterial() throws Exception {
mPlatformKeyManager.init(USER_ID_FIXTURE);
@@ -259,6 +299,9 @@ public class PlatformKeyManagerTest {
when(mKeyStoreProxy
.containsAlias("com.android.server.locksettings.recoverablekeystore/"
+ "platform/42/1/encrypt")).thenReturn(true);
+ when(mKeyStoreProxy.getKey(
+ eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"),
+ any())).thenReturn(generateAndroidKeyStoreKey());
mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE);
@@ -281,6 +324,9 @@ public class PlatformKeyManagerTest {
when(mKeyStoreProxy
.containsAlias("com.android.server.locksettings.recoverablekeystore/"
+ "platform/42/2/decrypt")).thenReturn(true);
+ when(mKeyStoreProxy.getKey(
+ eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"),
+ any())).thenReturn(generateAndroidKeyStoreKey());
mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE);
@@ -352,6 +398,9 @@ public class PlatformKeyManagerTest {
doThrow(new UnrecoverableKeyException()).when(mKeyStoreProxy).getKey(
eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"),
any());
+ when(mKeyStoreProxy.getKey(
+ eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"),
+ any())).thenReturn(generateAndroidKeyStoreKey());
when(mKeyStoreProxy
.containsAlias("com.android.server.locksettings.recoverablekeystore/"
@@ -536,4 +585,34 @@ public class PlatformKeyManagerTest {
mProtectionParameterCaptor.capture());
return (KeyProtection) mProtectionParameterCaptor.getValue();
}
+
+ private AndroidKeyStoreSecretKey generateAndroidKeyStoreKey() throws Exception {
+ KeyGenerator keyGenerator = KeyGenerator.getInstance(
+ KEY_ALGORITHM,
+ ANDROID_KEY_STORE_PROVIDER);
+ keyGenerator.init(new KeyGenParameterSpec.Builder(TESTING_KEYSTORE_KEY_ALIAS,
+ KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ .build());
+ return (AndroidKeyStoreSecretKey) keyGenerator.generateKey();
+ }
+
+ class PlatformKeyManagerTestable extends PlatformKeyManager {
+ private IGateKeeperService mGateKeeperService;
+
+ PlatformKeyManagerTestable(
+ Context context,
+ KeyStoreProxy keyStoreProxy,
+ RecoverableKeyStoreDb database,
+ IGateKeeperService gateKeeperService) {
+ super(context, keyStoreProxy, database);
+ mGateKeeperService = gateKeeperService;
+ }
+
+ @Override
+ IGateKeeperService getGateKeeperService() {
+ return mGateKeeperService;
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 8d0365b534b5..95043810128a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -32,6 +32,7 @@ import static org.mockito.Mockito.verify;
import android.Manifest.permission;
import android.app.ActivityManager;
+import android.app.Person;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ShortcutInfo;
@@ -890,6 +891,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
.setText("text")
.setDisabledMessage("dismes")
.setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
+ .setPerson(makePerson("person", "personKey", "personUri"))
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setRank(123)
.setExtras(pb)
@@ -901,6 +903,8 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
.setTitle("x")
.setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+ .setPersons(list(makePerson("person1", "personKey1", "personUri1"),
+ makePerson("person2", "personKey2", "personUri2")).toArray(new Person[2]))
.setRank(456)
.build();
sorig2.setTimestamp(mInjectedCurrentTimeMillis);
@@ -936,6 +940,10 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
+ assertEquals(1, si.getPersons().length);
+ assertEquals("person", si.getPersons()[0].getName());
+ assertEquals("personKey", si.getPersons()[0].getKey());
+ assertEquals("personUri", si.getPersons()[0].getUri());
assertEquals(0, si.getRank());
assertEquals(1, si.getExtras().getInt("k"));
@@ -949,6 +957,8 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
// to test it.
si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_10);
assertEquals(1, si.getRank());
+ assertEquals(2, si.getPersons().length);
+ assertEquals("personUri2", si.getPersons()[1].getUri());
dumpUserFile(USER_10);
}
@@ -1114,6 +1124,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
.setDisabledMessage("dismes")
.setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+ .setPerson(makePerson("person", "personKey", "personUri"))
.setRank(123)
.setExtras(pb)
.build();
@@ -1150,6 +1161,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
+ assertEquals(0, si.getPersons().length); // Don't backup the persons field
assertEquals(0, si.getRank());
assertEquals(1, si.getExtras().getInt("k"));
diff --git a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
index 9f1cbcd7ec27..6a937fabd3ec 100644
--- a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
@@ -98,6 +98,15 @@ public class AttentionDetectorTest extends AndroidTestCase {
}
@Test
+ public void testUpdateUserActivity_schedulesTheNextCheck() {
+ long now = SystemClock.uptimeMillis();
+ mNextDimming = now;
+ mAttentionDetector.onUserActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH);
+ long nextTimeout = mAttentionDetector.updateUserActivity(mNextDimming + 5000L);
+ assertThat(nextTimeout).isEqualTo(mNextDimming + 5000L);
+ }
+
+ @Test
public void testOnUserActivity_ignoresAfterMaximumExtension() {
long now = SystemClock.uptimeMillis();
mAttentionDetector.onUserActivity(now - 15000L, PowerManager.USER_ACTIVITY_EVENT_TOUCH);
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
index 4e43d002d4ae..8caa39dfc9e7 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
@@ -1035,6 +1035,15 @@ public class AppTimeLimitControllerTests {
0L, group.getUsageRemaining());
}
+ /** Verify that a limit of 0 is allowed for the special case of re-registering an observer. */
+ @Test
+ public void testAppUsageLimitObserver_ZeroTimeLimitIsAllowed() {
+ addAppUsageLimitObserver(OBS_ID1, GROUP1, 0);
+ AppTimeLimitController.AppUsageLimitGroup group = getAppUsageLimitObserver(UID, OBS_ID1);
+ assertNotNull("Observer wasn't added", group);
+ assertEquals("Usage remaining was not 0.", 0, group.getUsageRemaining());
+ }
+
private void startUsage(String packageName) {
mController.noteUsageStart(packageName, USER_ID);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 2de4ae02828c..23bae8881aa1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -24,6 +24,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
+
import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -35,9 +36,7 @@ import android.content.Intent;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import android.util.SparseIntArray;
-import android.util.proto.ProtoOutputStream;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 4073ff106592..8c36905d8422 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -183,11 +183,14 @@ public class ActivityRecordTests extends ActivityTestsBase {
.thenReturn(navBarPosition);
mTask.getConfiguration().windowConfiguration.setAppBounds(taskBounds);
mActivity.info.maxAspectRatio = aspectRatio;
- mActivity.ensureActivityConfiguration(
- 0 /* globalChanges */, false /* preserveWindow */);
+ ensureActivityConfiguration();
assertEquals(expectedActivityBounds, mActivity.getBounds());
}
+ private void ensureActivityConfiguration() {
+ mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
+ }
+
@Test
public void testCanBeLaunchedOnDisplay() {
mService.mSupportsMultiWindow = true;
@@ -281,7 +284,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
- mActivity.ensureActivityConfiguration(0, false, false);
+ ensureActivityConfiguration();
assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE,
mActivity.mRelaunchReason);
@@ -305,7 +308,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
- mActivity.ensureActivityConfiguration(0, false, false);
+ ensureActivityConfiguration();
assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE,
mActivity.mRelaunchReason);
@@ -327,7 +330,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
mActivity.mRelaunchReason =
ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
- mActivity.ensureActivityConfiguration(0, false, false);
+ ensureActivityConfiguration();
assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE,
mActivity.mRelaunchReason);
@@ -433,4 +436,46 @@ public class ActivityRecordTests extends ActivityTestsBase {
stack.getDisplay().removeChild(stack);
}
}
+
+ @Test
+ public void testFixedScreenConfigurationWhenMovingToDisplay() {
+ // Initialize different bounds on a new display.
+ final ActivityDisplay newDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+ newDisplay.setBounds(0, 0, 1000, 2000);
+ newDisplay.getConfiguration().densityDpi = 300;
+
+ mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds());
+ mTask.getConfiguration().densityDpi = 200;
+ when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn(
+ ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+ mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+ mActivity.info.maxAspectRatio = 1.5f;
+ ensureActivityConfiguration();
+ final Rect originalBounds = new Rect(mActivity.getBounds());
+ final int originalDpi = mActivity.getConfiguration().densityDpi;
+
+ // Move the non-resizable activity to the new display.
+ mStack.reparent(newDisplay, true /* onTop */, false /* displayRemoved */);
+ ensureActivityConfiguration();
+
+ assertEquals(originalBounds, mActivity.getBounds());
+ assertEquals(originalDpi, mActivity.getConfiguration().densityDpi);
+ }
+
+ @Test
+ public void testFixedScreenBoundsWhenDisplaySizeChanged() {
+ when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn(
+ ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+ mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds());
+ mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+ mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+ ensureActivityConfiguration();
+ final Rect originalBounds = new Rect(mActivity.getBounds());
+
+ // Change the size of current display.
+ mStack.getDisplay().setBounds(0, 0, 1000, 2000);
+ ensureActivityConfiguration();
+
+ assertEquals(originalBounds, mActivity.getBounds());
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 60f1ae26f5dd..392b0106c8e5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -61,7 +61,6 @@ import static org.mockito.ArgumentMatchers.eq;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
-import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -643,7 +642,7 @@ public class ActivityStarterTests extends ActivityTestsBase {
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
false, false, false, true, false);
runAndVerifyBackgroundActivityStartsSubtest(
- "disallowed_callingPackageIsDeviceOwner_notAborted", false,
+ "disallowed_callingPackageNameIsDeviceOwner_notAborted", false,
UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
false, false, false, false, true);
@@ -655,7 +654,7 @@ public class ActivityStarterTests extends ActivityTestsBase {
boolean hasForegroundActivities, boolean callerIsRecents,
boolean callerIsTempWhitelisted,
boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges,
- boolean isCallingPackageDeviceOwner) {
+ boolean isCallingPackageNameDeviceOwner) {
// window visibility
doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
.isAnyNonToastWindowVisibleForUid(callingUid);
@@ -681,9 +680,8 @@ public class ActivityStarterTests extends ActivityTestsBase {
// caller is instrumenting with background activity starts privileges
callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges,
callerIsInstrumentingWithBackgroundActivityStartPrivileges);
- // caller is device owner
- DevicePolicyManager dpmMock = mService.getDevicePolicyManager();
- doReturn(isCallingPackageDeviceOwner).when(dpmMock).isDeviceOwnerApp(any());
+ // calling package name is whitelisted
+ doReturn(isCallingPackageNameDeviceOwner).when(mService).isDeviceOwner(any());
final ActivityOptions options = spy(ActivityOptions.makeBasic());
ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index e27dd94b1a2c..abc0bd64c0e0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -42,7 +42,6 @@ import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
-import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -72,8 +71,10 @@ import com.android.server.am.PendingIntentController;
import com.android.server.appop.AppOpsService;
import com.android.server.firewall.IntentFirewall;
import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.server.wm.utils.MockTracker;
import org.junit.After;
+import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
@@ -88,6 +89,8 @@ import java.util.List;
class ActivityTestsBase {
private static int sNextDisplayId = DEFAULT_DISPLAY + 1;
+ private static MockTracker sMockTracker;
+
@Rule
public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
new DexmakerShareClassLoaderRule();
@@ -107,9 +110,17 @@ class ActivityTestsBase {
@BeforeClass
public static void setUpOnceBase() {
+ sMockTracker = new MockTracker();
+
AttributeCache.init(getInstrumentation().getTargetContext());
}
+ @AfterClass
+ public static void tearDownOnceBase() {
+ sMockTracker.close();
+ sMockTracker = null;
+ }
+
@Before
public void setUpBase() {
mTestInjector.setUp();
@@ -425,7 +436,6 @@ class ActivityTestsBase {
spyOn(getLifecycleManager());
spyOn(getLockTaskController());
doReturn(mock(IPackageManager.class)).when(this).getPackageManager();
- doReturn(mock(DevicePolicyManager.class)).when(this).getDevicePolicyManager();
// allow background activity starts by default
doReturn(true).when(this).isBackgroundActivityStartsEnabled();
doNothing().when(this).updateCpuStats();
@@ -657,12 +667,11 @@ class ActivityTestsBase {
private static WindowManagerService sMockWindowManagerService;
private static WindowManagerService prepareMockWindowManager() {
- if (sMockWindowManagerService != null) {
- return sMockWindowManagerService;
+ if (sMockWindowManagerService == null) {
+ sMockWindowManagerService = mock(WindowManagerService.class);
}
- final WindowManagerService service = mock(WindowManagerService.class);
- service.mRoot = mock(RootWindowContainer.class);
+ sMockWindowManagerService.mRoot = mock(RootWindowContainer.class);
doAnswer((InvocationOnMock invocationOnMock) -> {
final Runnable runnable = invocationOnMock.<Runnable>getArgument(0);
@@ -670,10 +679,9 @@ class ActivityTestsBase {
runnable.run();
}
return null;
- }).when(service).inSurfaceTransaction(any());
+ }).when(sMockWindowManagerService).inSurfaceTransaction(any());
- sMockWindowManagerService = service;
- return service;
+ return sMockWindowManagerService;
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index defe9811ebcf..2627ec762d7a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -16,24 +16,30 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import android.graphics.Rect;
import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+import android.view.Display;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
import android.view.RemoteAnimationTarget;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
-import org.junit.Before;
import org.junit.Test;
/**
@@ -43,20 +49,27 @@ import org.junit.Test;
* atest WmTests:AppChangeTransitionTests
*/
@SmallTest
+@Presubmit
public class AppChangeTransitionTests extends WindowTestsBase {
private TaskStack mStack;
private Task mTask;
private WindowTestUtils.TestAppWindowToken mToken;
- @Before
- public void setUp() throws Exception {
- mStack = createTaskStackOnDisplay(mDisplayContent);
+ public void setUpOnDisplay(DisplayContent dc) {
+ mStack = createTaskStackOnDisplay(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, dc);
mTask = createTaskInStack(mStack, 0 /* userId */);
- mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
+ mToken = WindowTestUtils.createTestAppWindowToken(dc);
mToken.mSkipOnParentChanged = false;
mTask.addChild(mToken, 0);
+
+ // Set a remote animator with snapshot disabled. Snapshots don't work in wmtests.
+ RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
+ RemoteAnimationAdapter adapter =
+ new RemoteAnimationAdapter(new TestRemoteAnimationRunner(), 10, 1, false);
+ definition.addRemoteAnimation(TRANSIT_TASK_CHANGE_WINDOWING_MODE, adapter);
+ dc.registerRemoteAnimations(definition);
}
class TestRemoteAnimationRunner implements IRemoteAnimationRunner {
@@ -85,14 +98,58 @@ public class AppChangeTransitionTests extends WindowTestsBase {
@Test
public void testModeChangeRemoteAnimatorNoSnapshot() {
- RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
- RemoteAnimationAdapter adapter =
- new RemoteAnimationAdapter(new TestRemoteAnimationRunner(), 10, 1, false);
- definition.addRemoteAnimation(TRANSIT_TASK_CHANGE_WINDOWING_MODE, adapter);
- mDisplayContent.registerRemoteAnimations(definition);
+ // setup currently defaults to no snapshot.
+ setUpOnDisplay(mDisplayContent);
mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
assertEquals(1, mDisplayContent.mChangingApps.size());
+
+ // Verify we are in a change transition, but without a snapshot.
+ // Though, the test will actually have crashed by now if a snapshot is attempted.
+ assertNull(mToken.getThumbnail());
+ assertTrue(mToken.isInChangeTransition());
+
+ waitUntilHandlersIdle();
+ mToken.removeImmediately();
+ }
+
+ @Test
+ public void testCancelPendingChangeOnRemove() {
+ // setup currently defaults to no snapshot.
+ setUpOnDisplay(mDisplayContent);
+
+ mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ assertEquals(1, mDisplayContent.mChangingApps.size());
+ assertTrue(mToken.isInChangeTransition());
+
+ // Removing the app-token from the display should clean-up the
+ // the change leash.
+ mDisplayContent.removeAppToken(mToken.token);
+ assertEquals(0, mDisplayContent.mChangingApps.size());
+ assertFalse(mToken.isInChangeTransition());
+
+ waitUntilHandlersIdle();
+ mToken.removeImmediately();
+ }
+
+ @Test
+ public void testNoChangeWhenMoveDisplay() {
+ mDisplayContent.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ final DisplayContent dc1 = createNewDisplay(Display.STATE_ON);
+ dc1.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ setUpOnDisplay(dc1);
+
+ assertEquals(WINDOWING_MODE_FREEFORM, mTask.getWindowingMode());
+
+ // Reparenting to a display with different windowing mode may trigger
+ // a change transition internally, but it should be cleaned-up once
+ // the display change is complete.
+ mStack.reparent(mDisplayContent.getDisplayId(), new Rect(), true);
+
+ assertEquals(WINDOWING_MODE_FULLSCREEN, mTask.getWindowingMode());
+
+ // Make sure we're not waiting for a change animation (no leash)
+ assertFalse(mToken.isInChangeTransition());
assertNull(mToken.getThumbnail());
waitUntilHandlersIdle();
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index bc62de12373d..1dd72ec4fd71 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -44,13 +44,13 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
+import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.Surface;
import android.view.WindowManager;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Before;
@@ -62,7 +62,6 @@ import org.junit.Test;
* Build/Install/Run:
* atest FrameworksServicesTests:AppWindowTokenTests
*/
-@FlakyTest(bugId = 68267650)
@SmallTest
@Presubmit
public class AppWindowTokenTests extends WindowTestsBase {
@@ -79,6 +78,7 @@ public class AppWindowTokenTests extends WindowTestsBase {
mTask = createTaskInStack(mStack, 0 /* userId */);
mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
+ mToken.mSkipOnParentChanged = false;
mTask.addChild(mToken, 0);
}
@@ -166,6 +166,8 @@ public class AppWindowTokenTests extends WindowTestsBase {
mDisplayContent.updateOrientationFromAppTokens(
mDisplayContent.getRequestedOverrideConfiguration(),
null /* freezeThisOneIfNeeded */, false /* forceUpdate */);
+ // In this test, DC will not get config update. Set the waiting flag to false.
+ mDisplayContent.mWaitingForConfig = false;
mWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
assertEquals(SCREEN_ORIENTATION_REVERSE_LANDSCAPE, mDisplayContent.getLastOrientation());
assertTrue(appWindow.mResizeReported);
@@ -211,6 +213,48 @@ public class AppWindowTokenTests extends WindowTestsBase {
}
@Test
+ public void testSizeCompatBounds() {
+ // The real surface transaction is unnecessary.
+ mToken.setSkipPrepareSurfaces(true);
+
+ final Rect fixedBounds = mToken.getRequestedOverrideConfiguration().windowConfiguration
+ .getBounds();
+ fixedBounds.set(0, 0, 1200, 1600);
+ final Configuration newParentConfig = mTask.getConfiguration();
+
+ // Change the size of the container to two times smaller with insets.
+ newParentConfig.windowConfiguration.setAppBounds(200, 0, 800, 800);
+ final Rect containerAppBounds = newParentConfig.windowConfiguration.getAppBounds();
+ final Rect containerBounds = newParentConfig.windowConfiguration.getBounds();
+ containerBounds.set(0, 0, 600, 800);
+ mToken.onConfigurationChanged(newParentConfig);
+
+ assertTrue(mToken.inSizeCompatMode());
+ assertEquals(containerAppBounds, mToken.getBounds());
+ assertEquals((float) containerAppBounds.width() / fixedBounds.width(),
+ mToken.getSizeCompatScale(), 0.0001f /* delta */);
+
+ // Change the width of the container to two times bigger.
+ containerAppBounds.set(0, 0, 2400, 1600);
+ containerBounds.set(containerAppBounds);
+ mToken.onConfigurationChanged(newParentConfig);
+
+ assertTrue(mToken.inSizeCompatMode());
+ // Don't scale up, so the bounds keep the same as the fixed width.
+ assertEquals(fixedBounds.width(), mToken.getBounds().width());
+ // Assert the position is horizontal center.
+ assertEquals((containerAppBounds.width() - fixedBounds.width()) / 2,
+ mToken.getBounds().left);
+ assertEquals(1f, mToken.getSizeCompatScale(), 0.0001f /* delta */);
+
+ // Change the width of the container to fit the fixed bounds.
+ containerBounds.set(0, 0, 1200, 2000);
+ mToken.onConfigurationChanged(newParentConfig);
+ // Assert don't use fixed bounds because the region is enough.
+ assertFalse(mToken.inSizeCompatMode());
+ }
+
+ @Test
@Presubmit
public void testGetOrientation() {
mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
@@ -257,7 +301,6 @@ public class AppWindowTokenTests extends WindowTestsBase {
}
@Test
- @FlakyTest(detail = "Promote once confirmed non-flaky")
public void testStuckExitingWindow() {
final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
"closingWindow");
@@ -384,6 +427,7 @@ public class AppWindowTokenTests extends WindowTestsBase {
// bottom one.
tokenTop.setVisibility(false, false);
tokenBottom.transferStartingWindowFromHiddenAboveTokenIfNeeded();
+ waitUntilHandlersIdle();
// Assert that the bottom window now has the starting window.
assertNoStartingWindow(tokenTop);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
index 2f90baaceb99..1e02a12e83db 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
@@ -46,6 +46,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.platform.test.annotations.Presubmit;
import android.util.Log;
import android.view.IWindowManager;
@@ -71,7 +72,7 @@ import java.util.concurrent.TimeUnit;
* atest WmTests:AssistDataRequesterTest
*/
@MediumTest
-@FlakyTest(bugId = 113616538)
+@Presubmit
public class AssistDataRequesterTest extends ActivityTestsBase {
private static final String TAG = AssistDataRequesterTest.class.getSimpleName();
@@ -154,6 +155,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase {
.checkOpNoThrow(eq(OP_ASSIST_SCREENSHOT), anyInt(), anyString());
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testRequestData() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -174,6 +176,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase {
assertReceivedDataCount(0, 0, 0, 0);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testCurrentAppDisallow_expectNullCallbacks() throws Exception {
setupMocks(!CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -184,6 +187,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase {
assertReceivedDataCount(0, 1, 0, 1);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testProcessPendingData() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -241,6 +245,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase {
assertReceivedDataCount(0, 1, 0, 1);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testDisallowAssistContextExtras_expectNullDataCallbacks() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -254,6 +259,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase {
assertReceivedDataCount(0, 1, 0, 1);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testNoFetchScreenshots_expectNoScreenshotCallbacks() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -264,6 +270,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase {
assertReceivedDataCount(5, 5, 0, 0);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testDisallowAssistScreenshot_expectNullScreenshotCallback() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 198e7ce63f52..b15e99aaa8c2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -60,6 +60,7 @@ import com.android.server.LocalServices;
import com.android.server.UiThread;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.wm.utils.WmDisplayCutout;
import org.junit.After;
import org.junit.Before;
@@ -113,6 +114,7 @@ public class DisplayRotationTests {
public static void setUpOnce() {
sMockWm = mock(WindowManagerService.class);
sMockWm.mPowerManagerInternal = mock(PowerManagerInternal.class);
+ sMockWm.mPolicy = mock(WindowManagerPolicy.class);
}
@Before
@@ -807,6 +809,8 @@ public class DisplayRotationTests {
mMockDisplayContent = mock(WindowTestUtils.TestDisplayContent.class);
mMockDisplayContent.isDefaultDisplay = mIsDefaultDisplay;
+ when(mMockDisplayContent.calculateDisplayCutoutForRotation(anyInt()))
+ .thenReturn(WmDisplayCutout.NO_CUTOUT);
mMockDisplayPolicy = mock(DisplayPolicy.class);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
index 0c363de36328..a0546d7623e7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
@@ -19,11 +19,11 @@ package com.android.server.wm;
import static android.view.InsetsState.TYPE_TOP_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -31,8 +31,6 @@ import android.platform.test.annotations.Presubmit;
import android.view.InsetsSource;
import android.view.InsetsState;
-import org.junit.Before;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Before;
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index 11526a85aafb..bc62e8c5ab24 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -35,7 +35,6 @@ import androidx.test.filters.SmallTest;
import org.junit.Test;
@SmallTest
-@FlakyTest(detail = "Promote once confirmed non-flaky")
@Presubmit
public class InsetsStateControllerTest extends WindowTestsBase {
@@ -48,6 +47,7 @@ public class InsetsStateControllerTest extends WindowTestsBase {
assertNotNull(getController().getInsetsForDispatch(app).getSource(TYPE_TOP_BAR));
}
+ @FlakyTest(bugId = 69229402)
@Test
public void testStripForDispatch_own() {
final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
@@ -57,6 +57,7 @@ public class InsetsStateControllerTest extends WindowTestsBase {
assertEquals(new InsetsState(), getController().getInsetsForDispatch(topBar));
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testStripForDispatch_navBar() {
final WindowState navBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
@@ -68,6 +69,7 @@ public class InsetsStateControllerTest extends WindowTestsBase {
assertEquals(new InsetsState(), getController().getInsetsForDispatch(navBar));
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testBarControllingWinChanged() {
final WindowState navBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
@@ -80,6 +82,7 @@ public class InsetsStateControllerTest extends WindowTestsBase {
assertEquals(2, controls.length);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testControlRevoked() {
final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
@@ -91,6 +94,7 @@ public class InsetsStateControllerTest extends WindowTestsBase {
assertNull(getController().getControlsForDispatch(app));
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testControlRevoked_animation() {
final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
diff --git a/services/tests/wmtests/src/com/android/server/wm/KeyguardDisableHandlerTest.java b/services/tests/wmtests/src/com/android/server/wm/KeyguardDisableHandlerTest.java
index ce22788f7cb9..df26679dc1fb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/KeyguardDisableHandlerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/KeyguardDisableHandlerTest.java
@@ -34,6 +34,7 @@ import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
import android.util.SparseBooleanArray;
import com.android.server.wm.LockTaskController.LockTaskToken;
@@ -43,6 +44,7 @@ import org.junit.Test;
import java.lang.reflect.Constructor;
+@Presubmit
public class KeyguardDisableHandlerTest {
private KeyguardDisableHandler mKeyguardDisable;
diff --git a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
index 86bf3dbb6973..b769fcecc469 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
@@ -24,7 +24,6 @@ import android.app.ActivityOptions;
import android.platform.test.annotations.Presubmit;
import android.view.RemoteAnimationAdapter;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.server.testutils.OffsettableClock;
diff --git a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
index c3d2f33b17dd..83274401f13d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
@@ -28,7 +28,6 @@ import static org.junit.Assert.assertTrue;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import org.junit.After;
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index cc6a58a81635..763ea6293fcc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -112,8 +112,8 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
}
}
- @FlakyTest(bugId = 117117823)
@Test
+ @FlakyTest(bugId = 117117823)
public void testIncludedApps_expectTargetAndVisible() {
mWm.setRecentsAnimationController(mController);
final AppWindowToken homeAppWindow = createAppWindowToken(mDisplayContent,
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 67ee4ad91d91..94def2bb7846 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -67,6 +67,7 @@ import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -142,7 +143,8 @@ public class RootActivityContainerTests extends ActivityTestsBase {
private static void ensureStackPlacement(ActivityStack stack, TaskRecord... tasks) {
final ArrayList<TaskRecord> stackTasks = stack.getAllTasks();
- assertEquals(stackTasks.size(), tasks != null ? tasks.length : 0);
+ assertEquals("Expecting " + Arrays.deepToString(tasks) + " got " + stackTasks,
+ stackTasks.size(), tasks != null ? tasks.length : 0);
if (tasks == null) {
return;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
index dad6c952d7ab..71118521acf5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
@@ -21,7 +21,6 @@ import static org.junit.Assert.assertEquals;
import android.app.ActivityOptions;
import android.platform.test.annotations.Presubmit;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import org.junit.Test;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
index dfdbf323365f..6cce9f088ee4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
@@ -167,7 +167,6 @@ public class SurfaceAnimationRunnerTest extends WindowTestsBase {
verify(mMockAnimationSpec, atLeastOnce()).apply(any(), any(), eq(0L));
}
- @FlakyTest(bugId = 74780584)
@Test
public void testDeferStartingAnimations() throws Exception {
mSurfaceAnimationRunner.deferStartingAnimations();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
index 8c32e8cea93c..88ac96d74df6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -34,7 +34,6 @@ import android.view.SurfaceControl.Builder;
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.server.wm.SurfaceAnimator.Animatable;
@@ -51,7 +50,7 @@ import org.mockito.MockitoAnnotations;
* Test class for {@link SurfaceAnimatorTest}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:SurfaceAnimatorTest
+ * atest WmTests:SurfaceAnimatorTest
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
index 12ed3c28161f..9dfeadf878e0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
@@ -29,8 +29,6 @@ import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
import android.util.SparseBooleanArray;
-import androidx.test.filters.FlakyTest;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
index c595868db484..2377df406fbc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
@@ -34,10 +34,12 @@ import static org.junit.Assert.assertTrue;
import android.app.IActivityTaskManager;
import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Before;
@@ -50,6 +52,8 @@ import org.junit.Test;
* atest WmTests:TaskPositionerTests
*/
@SmallTest
+@Presubmit
+@FlakyTest
public class TaskPositionerTests extends WindowTestsBase {
private static final boolean DEBUGGING = false;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
index 8c6ac23c9202..1e58e413dd1b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -43,7 +43,6 @@ import org.junit.Test;
* Build/Install/Run:
* atest FrameworksServicesTests:TaskPositioningControllerTests
*/
-@FlakyTest(bugId = 117924387)
@SmallTest
@Presubmit
public class TaskPositioningControllerTests extends WindowTestsBase {
@@ -90,6 +89,7 @@ public class TaskPositioningControllerTests extends WindowTestsBase {
assertNull(mTarget.getDragWindowHandleLocked());
}
+ @FlakyTest(bugId = 69229402)
@Test
public void testHandleTapOutsideTask() {
synchronized (mWm.mGlobalLock) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index 4a734e5256f6..dcca3167c752 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -35,9 +35,11 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
import android.support.test.uiautomator.UiDevice;
import android.text.TextUtils;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import com.android.internal.annotations.GuardedBy;
@@ -76,6 +78,7 @@ public class TaskStackChangedListenerTest {
}
@Test
+ @Presubmit
public void testTaskStackChanged_afterFinish() throws Exception {
registerTaskStackChangedListener(new TaskStackListener() {
@Override
@@ -87,7 +90,8 @@ public class TaskStackChangedListenerTest {
});
Context context = getInstrumentation().getContext();
- context.startActivity(new Intent(context, ActivityA.class));
+ context.startActivity(
+ new Intent(context, ActivityA.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
UiDevice.getInstance(getInstrumentation()).waitForIdle();
synchronized (sLock) {
assertTrue(sTaskStackChangedCalled);
@@ -96,6 +100,7 @@ public class TaskStackChangedListenerTest {
}
@Test
+ @FlakyTest(bugId = 119893767)
public void testTaskDescriptionChanged() throws Exception {
final Object[] params = new Object[2];
final CountDownLatch latch = new CountDownLatch(1);
@@ -124,6 +129,7 @@ public class TaskStackChangedListenerTest {
}
@Test
+ @FlakyTest(bugId = 119893767)
public void testActivityRequestedOrientationChanged() throws Exception {
final int[] params = new int[2];
final CountDownLatch latch = new CountDownLatch(1);
@@ -146,6 +152,7 @@ public class TaskStackChangedListenerTest {
* Tests for onTaskCreated, onTaskMovedToFront, onTaskRemoved and onTaskRemovalStarted.
*/
@Test
+ @FlakyTest(bugId = 119893767)
public void testTaskChangeCallBacks() throws Exception {
final Object[] params = new Object[2];
final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1);
@@ -221,7 +228,8 @@ public class TaskStackChangedListenerTest {
final ActivityMonitor monitor = new ActivityMonitor(activityClass.getName(), null, false);
getInstrumentation().addMonitor(monitor);
final Context context = getInstrumentation().getContext();
- context.startActivity(new Intent(context, activityClass));
+ context.startActivity(
+ new Intent(context, activityClass).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
final TestActivity activity = (TestActivity) monitor.waitForActivityWithTimeout(1000);
if (activity == null) {
throw new RuntimeException("Timed out waiting for Activity");
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
index b151fb7a613c..e540b3a9db89 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
@@ -61,7 +61,7 @@ import com.android.server.policy.WindowManagerPolicy;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.quality.Strictness;
-import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* A Test utility class to create a mock {@link WindowManagerService} instance for tests.
@@ -71,6 +71,8 @@ class TestSystemServices {
private static WindowManagerService sService;
private static TestWindowManagerPolicy sPolicy;
+ static AtomicBoolean sCurrentMessagesProcessed = new AtomicBoolean(false);
+
static void setUpWindowManagerService() {
sMockitoSession = mockitoSession()
.spyStatic(LockGuard.class)
@@ -88,6 +90,7 @@ class TestSystemServices {
sPolicy = null;
sMockitoSession.finishMocking();
+ sMockitoSession = null;
}
private static void setUpTestWindowService() {
@@ -194,21 +197,23 @@ class TestSystemServices {
}
private static void waitHandlerIdle(Handler handler) {
- if (!handler.hasMessagesOrCallbacks()) {
- return;
- }
- final CountDownLatch latch = new CountDownLatch(1);
- // Wait for delayed messages are processed.
- handler.getLooper().getQueue().addIdleHandler(() -> {
- if (handler.hasMessagesOrCallbacks()) {
- return true; // keep idle handler.
+ synchronized (sCurrentMessagesProcessed) {
+ // Add a message to the handler queue and make sure it is fully processed before we move
+ // on. This makes sure all previous messages in the handler are fully processed vs. just
+ // popping them from the message queue.
+ sCurrentMessagesProcessed.set(false);
+ handler.post(() -> {
+ synchronized (sCurrentMessagesProcessed) {
+ sCurrentMessagesProcessed.set(true);
+ sCurrentMessagesProcessed.notifyAll();
+ }
+ });
+ while (!sCurrentMessagesProcessed.get()) {
+ try {
+ sCurrentMessagesProcessed.wait();
+ } catch (InterruptedException e) {
+ }
}
- latch.countDown();
- return false; // remove idle handler.
- });
- try {
- latch.await();
- } catch (InterruptedException e) {
}
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index bfb9193551f2..849772a4a26d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -156,7 +156,8 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
}
@Override
- public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
+ public int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
+ int policyFlags) {
return 0;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java
index 64ceb1bf8dff..d6608f1cabdc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java
@@ -49,7 +49,7 @@ import org.junit.Test;
* Test class to for {@link android.app.WindowConfiguration}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:WindowConfigurationTests
+ * atest WmTests:WindowConfigurationTests
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java
index af8ccc981bae..fc7863524240 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java
@@ -26,7 +26,6 @@ import static org.junit.Assert.assertTrue;
import android.content.res.Configuration;
import android.platform.test.annotations.Presubmit;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Test;
@@ -35,7 +34,7 @@ import org.junit.Test;
* Test class for {@link WindowContainerController}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:WindowContainerControllerTests
+ * atest WmTests:WindowContainerControllerTests
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index a9a76c2e9506..b93c994f4d8f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -47,7 +47,6 @@ import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Test;
@@ -59,11 +58,10 @@ import java.util.Comparator;
* Test class for {@link WindowContainer}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:WindowContainerTests
+ * atest WmTests:WindowContainerTests
*/
@SmallTest
@Presubmit
-@FlakyTest(bugId = 74078662)
public class WindowContainerTests extends WindowTestsBase {
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index 0a4a8a43fbc5..fb30f8b2b107 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -449,8 +449,7 @@ public class WindowFrameTests extends WindowTestsBase {
// Now simulate switch to fullscreen for letterboxed app.
final int xInset = logicalWidth / 10;
- final int yInset = logicalWidth / 10;
- final Rect cf = new Rect(xInset, yInset, logicalWidth - xInset, logicalHeight - yInset);
+ final Rect cf = new Rect(xInset, 0, logicalWidth - xInset, logicalHeight);
Configuration config = new Configuration(w.mAppToken.getRequestedOverrideConfiguration());
config.windowConfiguration.setBounds(cf);
w.mAppToken.onRequestedOverrideConfigurationChanged(config);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index a4948899c855..114eac911bd7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -151,6 +151,7 @@ public class WindowTestUtils {
/** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
public static class TestAppWindowToken extends AppWindowToken {
boolean mOnTop = false;
+ private boolean mSkipPrepareSurfaces;
private Transaction mPendingTransactionOverride;
boolean mSkipOnParentChanged = true;
@@ -213,6 +214,17 @@ public class WindowTestUtils {
return mOnTop;
}
+ @Override
+ void prepareSurfaces() {
+ if (!mSkipPrepareSurfaces) {
+ super.prepareSurfaces();
+ }
+ }
+
+ void setSkipPrepareSurfaces(boolean ignore) {
+ mSkipPrepareSurfaces = ignore;
+ }
+
void setPendingTransaction(Transaction transaction) {
mPendingTransactionOverride = transaction;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 3cb28140e2ea..a83bf2af613e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -50,6 +50,7 @@ import android.view.IWindow;
import android.view.WindowManager;
import com.android.server.AttributeCache;
+import com.android.server.wm.utils.MockTracker;
import org.junit.After;
import org.junit.AfterClass;
@@ -77,6 +78,8 @@ class WindowTestsBase {
private static int sNextDisplayId = DEFAULT_DISPLAY + 1;
static int sNextStackId = 1000;
+ private static MockTracker sMockTracker;
+
/** Non-default display. */
DisplayContent mDisplayContent;
DisplayInfo mDisplayInfo = new DisplayInfo();
@@ -109,11 +112,18 @@ class WindowTestsBase {
TestSystemServices.setUpWindowManagerService();
+ // MockTracker needs to be initialized after TestSystemServices because we don't want to
+ // track static mocks.
+ sMockTracker = new MockTracker();
+
sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
}
@AfterClass
- public static void tearDonwOnceBase() {
+ public static void tearDownOnceBase() {
+ sMockTracker.close();
+ sMockTracker = null;
+
TestSystemServices.tearDownWindowManagerService();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
index d55688665f70..4cdbea0bfb56 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
@@ -28,7 +28,6 @@ import static org.junit.Assert.assertTrue;
import android.platform.test.annotations.Presubmit;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Test;
@@ -37,7 +36,7 @@ import org.junit.Test;
* Tests for the {@link WindowToken} class.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:WindowTokenTests
+ * atest WmTests:WindowTokenTests
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
index b6b9a861a282..3c6e2405adff 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
@@ -34,8 +34,8 @@ import android.content.Context;
import android.platform.test.annotations.Presubmit;
import android.testing.DexmakerShareClassLoaderRule;
import android.util.proto.ProtoOutputStream;
+import android.view.Choreographer;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.internal.util.Preconditions;
@@ -58,7 +58,7 @@ import java.nio.charset.StandardCharsets;
* Test class for {@link WindowTracing}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:WindowTracingTest
+ * atest WmTests:WindowTracingTest
*/
@SmallTest
@Presubmit
@@ -74,6 +74,8 @@ public class WindowTracingTest {
@Mock
private WindowManagerService mWmMock;
+ @Mock
+ private Choreographer mChoreographer;
private WindowTracing mWindowTracing;
private File mFile;
@@ -85,7 +87,9 @@ public class WindowTracingTest {
mFile = testContext.getFileStreamPath("tracing_test.dat");
mFile.delete();
- mWindowTracing = new WindowTracing(mFile);
+ mWindowTracing = new WindowTracing(mFile, mWmMock, mChoreographer,
+ new WindowManagerGlobalLock());
+ mWindowTracing.setContinuousMode(false /* continuous */, null /* pw */);
}
@After
@@ -113,15 +117,14 @@ public class WindowTracingTest {
@Test
public void trace_discared_whenNotTracing() {
- mWindowTracing.traceStateLocked("where", mWmMock);
+ mWindowTracing.logState("where");
verifyZeroInteractions(mWmMock);
}
@Test
public void trace_dumpsWindowManagerState_whenTracing() throws Exception {
mWindowTracing.startTrace(mock(PrintWriter.class));
- mWindowTracing.traceStateLocked("where", mWmMock);
-
+ mWindowTracing.logState("where");
verify(mWmMock).writeToProtoLocked(any(), eq(WindowTraceLogLevel.TRIM));
}
@@ -147,7 +150,7 @@ public class WindowTracingTest {
WindowManagerTraceProto.WHERE, "TEST_WM_PROTO");
return null;
}).when(mWmMock).writeToProtoLocked(any(), any());
- mWindowTracing.traceStateLocked("TEST_WHERE", mWmMock);
+ mWindowTracing.logState("TEST_WHERE");
mWindowTracing.stopTrace(mock(PrintWriter.class));
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index 3dcea75b8ae5..f3b8a6265eb3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -51,9 +51,8 @@ import java.util.LinkedList;
* Tests for the {@link DisplayContent#assignChildLayers(SurfaceControl.Transaction)} method.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:ZOrderingTests
+ * atest WmTests:ZOrderingTests
*/
-@FlakyTest(bugId = 74078662)
@SmallTest
@Presubmit
public class ZOrderingTests extends WindowTestsBase {
@@ -207,6 +206,7 @@ public class ZOrderingTests extends WindowTestsBase {
return createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, name);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeWithNoTarget() {
mDisplayContent.mInputMethodTarget = null;
@@ -224,6 +224,7 @@ public class ZOrderingTests extends WindowTestsBase {
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeWithAppTarget() {
final WindowState imeAppTarget = createWindow("imeAppTarget");
@@ -243,6 +244,7 @@ public class ZOrderingTests extends WindowTestsBase {
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() {
final WindowState imeAppTarget = createWindow("imeAppTarget");
@@ -269,6 +271,7 @@ public class ZOrderingTests extends WindowTestsBase {
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() {
final WindowState appBelowImeTarget = createWindow("appBelowImeTarget");
@@ -292,6 +295,7 @@ public class ZOrderingTests extends WindowTestsBase {
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeNonAppImeTarget() {
final WindowState imeSystemOverlayTarget = createWindow(null, TYPE_SYSTEM_OVERLAY,
@@ -319,6 +323,7 @@ public class ZOrderingTests extends WindowTestsBase {
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForStatusBarImeTarget() {
mDisplayContent.mInputMethodTarget = mStatusBarWindow;
@@ -333,6 +338,7 @@ public class ZOrderingTests extends WindowTestsBase {
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testStackLayers() {
final WindowState anyWindow1 = createWindow("anyWindow");
@@ -398,6 +404,7 @@ public class ZOrderingTests extends WindowTestsBase {
assertWindowHigher(mediaOverlayChild, child);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testDockedDividerPosition() {
final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/CoordinateTransformsTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/CoordinateTransformsTest.java
index 649b785c992b..99ceb2011db3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/utils/CoordinateTransformsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/utils/CoordinateTransformsTest.java
@@ -31,6 +31,7 @@ import static org.junit.Assert.*;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
+import android.platform.test.annotations.Presubmit;
import android.view.DisplayInfo;
import org.junit.Before;
@@ -42,6 +43,7 @@ import org.junit.rules.ErrorCollector;
* Build/Install/Run:
* atest WmTests:CoordinateTransformsTest
*/
+@Presubmit
public class CoordinateTransformsTest {
private static final int W = 200;
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java b/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java
new file mode 100644
index 000000000000..1ce463bbbd9e
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.utils;
+
+import android.util.Log;
+
+import org.mockito.Mockito;
+import org.mockito.MockitoFramework;
+import org.mockito.internal.creation.settings.CreationSettings;
+import org.mockito.listeners.MockCreationListener;
+import org.mockito.mock.MockCreationSettings;
+
+import java.lang.reflect.Field;
+import java.util.IdentityHashMap;
+
+/**
+ * An util class used to track mock creation, and reset them when closing. Note only one instance is
+ * allowed at anytime, as Mockito framework throws exception if there is already a listener of the
+ * same type registered.
+ */
+public class MockTracker implements MockCreationListener, AutoCloseable {
+ private static final String TAG = "MockTracker";
+
+ private static final Field SPIED_INSTANCE_FIELD;
+
+ static {
+ try {
+ SPIED_INSTANCE_FIELD = CreationSettings.class.getDeclaredField("spiedInstance");
+ SPIED_INSTANCE_FIELD.setAccessible(true);
+ } catch (NoSuchFieldException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private final MockitoFramework mMockitoFramework = Mockito.framework();
+
+ private final IdentityHashMap<Object, Void> mMocks = new IdentityHashMap<>();
+
+ public MockTracker() {
+ mMockitoFramework.addListener(this);
+ }
+
+ @Override
+ public void onMockCreated(Object mock, MockCreationSettings settings) {
+ mMocks.put(mock, null);
+ clearSpiedInstanceIfNeeded(mock, settings);
+ }
+
+ // HACK: Changing Mockito core implementation details.
+ // TODO(b/123984854): Remove this once there is a real fix.
+ private void clearSpiedInstanceIfNeeded(Object mock, MockCreationSettings settings) {
+ if (mock != settings.getSpiedInstance()) {
+ // Not a spyOn instance.
+ return;
+ }
+ if (!(settings instanceof CreationSettings)) {
+ throw new IllegalStateException("Unexpected type of settings: " + settings.getClass());
+ }
+ try {
+ SPIED_INSTANCE_FIELD.set(settings, null);
+ Log.d(TAG, "Setting spiedInstance for " + mock + " to null.");
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void close() {
+ mMockitoFramework.removeListener(this);
+
+ for (final Object mock : mMocks.keySet()) {
+ try {
+ Mockito.reset(mock);
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to reset " + mock, e);
+ }
+ }
+ mMocks.clear();
+ }
+}
diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
index 873ada05bc27..731cbf42eca7 100644
--- a/services/usage/java/com/android/server/usage/AppTimeLimitController.java
+++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
@@ -840,7 +840,8 @@ public class AppTimeLimitController {
*/
public void addAppUsageLimitObserver(int requestingUid, int observerId, String[] observed,
long timeLimit, PendingIntent callbackIntent, @UserIdInt int userId) {
- if (timeLimit < getMinTimeLimit()) {
+ // Allow the special case of the limit being 0, but with no callback.
+ if (timeLimit != 0L && timeLimit < getMinTimeLimit()) {
throw new IllegalArgumentException("Time limit must be >= " + getMinTimeLimit());
}
synchronized (mLock) {
@@ -858,7 +859,7 @@ public class AppTimeLimitController {
"Too many app usage observers added by uid " + requestingUid);
}
group = new AppUsageLimitGroup(user, observerApp, observerId, observed, timeLimit,
- callbackIntent);
+ timeLimit == 0L ? null : callbackIntent);
observerApp.appUsageLimitGroups.append(observerId, group);
if (DEBUG) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index df2f45512465..af5278f222b8 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1377,7 +1377,7 @@ public class UsageStatsService extends SystemService implements
if (packages == null || packages.length == 0) {
throw new IllegalArgumentException("Must specify at least one package");
}
- if (callbackIntent == null) {
+ if (callbackIntent == null && timeLimitMs != 0L) {
throw new NullPointerException("callbackIntent can't be null");
}
final int callingUid = Binder.getCallingUid();
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 7d1f8ce75919..6382acf0511d 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -19,6 +19,7 @@ package android.telecom;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemClock;
@@ -571,6 +572,7 @@ public abstract class Conference extends Conferenceable {
* @return The primary connection.
* @hide
*/
+ @TestApi
@SystemApi
public Connection getPrimaryConnection() {
if (mUnmodifiableChildConnections == null || mUnmodifiableChildConnections.isEmpty()) {
diff --git a/telecomm/java/android/telecom/DefaultDialerManager.java b/telecomm/java/android/telecom/DefaultDialerManager.java
index aac0956d4339..e43b2b715321 100644
--- a/telecomm/java/android/telecom/DefaultDialerManager.java
+++ b/telecomm/java/android/telecom/DefaultDialerManager.java
@@ -22,7 +22,6 @@ import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
@@ -163,9 +162,7 @@ public class DefaultDialerManager {
final Intent dialIntentWithTelScheme = new Intent(Intent.ACTION_DIAL);
dialIntentWithTelScheme.setData(Uri.fromParts(PhoneAccount.SCHEME_TEL, "", null));
- packageNames = filterByIntent(context, packageNames, dialIntentWithTelScheme, userId);
- packageNames = requireInCallService(packageNames, userId, context);
- return packageNames;
+ return filterByIntent(context, packageNames, dialIntentWithTelScheme, userId);
}
public static List<String> getInstalledDialerApplications(Context context) {
@@ -223,35 +220,6 @@ public class DefaultDialerManager {
return result;
}
- private static List<String> requireInCallService(List<String> packageNames, int userId,
- Context context) {
- if (packageNames == null || packageNames.isEmpty()) {
- return new ArrayList<>();
- }
-
- final Intent intent = new Intent(InCallService.SERVICE_INTERFACE);
- final List<ResolveInfo> resolveInfoList = context.getPackageManager()
- .queryIntentServicesAsUser(intent, PackageManager.GET_META_DATA, userId);
- final List<String> result = new ArrayList<>();
- final int length = resolveInfoList.size();
- for (int i = 0; i < length; i++) {
- final ServiceInfo info = resolveInfoList.get(i).serviceInfo;
- if (info == null || info.metaData == null) {
- continue;
- }
- if (!info.metaData.getBoolean(TelecomManager.METADATA_IN_CALL_SERVICE_UI)) {
- continue;
- }
- if (info.metaData.getBoolean(TelecomManager.METADATA_IN_CALL_SERVICE_CAR_MODE_UI)) {
- continue;
- }
- if (packageNames.contains(info.packageName) && !result.contains(info.packageName)) {
- result.add(info.packageName);
- }
- }
-
- return result;
- }
private static TelecomManager getTelecomManager(Context context) {
return (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 0e17a3373a65..d5091680285b 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -22,6 +22,7 @@ import android.annotation.SuppressAutoDoc;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.app.role.RoleManagerCallback;
import android.content.ComponentName;
@@ -290,6 +291,19 @@ public class TelecomManager {
"android.telecom.extra.OUTGOING_CALL_EXTRAS";
/**
+ * An optional boolean extra on {@link android.content.Intent#ACTION_CALL_EMERGENCY} to tell
+ * whether the user's dial intent is emergency; this is required to specify when the dialed
+ * number is ambiguous, identified as both emergency number and any other non-emergency number;
+ * e.g. in some situation, 611 could be both an emergency number in a country and a
+ * non-emergency number of a carrier's customer service hotline.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_IS_USER_INTENT_EMERGENCY_CALL =
+ "android.telecom.extra.IS_USER_INTENT_EMERGENCY_CALL";
+
+ /**
* @hide
*/
public static final String EXTRA_UNKNOWN_CALL_HANDLE =
@@ -552,6 +566,7 @@ public class TelecomManager {
*
* @hide
*/
+ @TestApi
@SystemApi
public static final int TTY_MODE_OFF = 0;
@@ -561,6 +576,7 @@ public class TelecomManager {
*
* @hide
*/
+ @TestApi
@SystemApi
public static final int TTY_MODE_FULL = 1;
@@ -571,6 +587,7 @@ public class TelecomManager {
*
* @hide
*/
+ @TestApi
@SystemApi
public static final int TTY_MODE_HCO = 2;
@@ -581,6 +598,7 @@ public class TelecomManager {
*
* @hide
*/
+ @TestApi
@SystemApi
public static final int TTY_MODE_VCO = 3;
@@ -819,6 +837,7 @@ public class TelecomManager {
* @hide
*/
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @TestApi
@SystemApi
public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) {
try {
@@ -1521,6 +1540,7 @@ public class TelecomManager {
* @hide
*/
@SystemApi
+ @TestApi
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public @TtyMode int getCurrentTtyMode() {
try {
@@ -1969,6 +1989,7 @@ public class TelecomManager {
* @hide
*/
@SystemApi
+ @TestApi
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public boolean isInEmergencyCall() {
try {
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 4539ab3dc310..a1c32b5f80a3 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -2717,6 +2717,41 @@ public final class Telephony {
Uri RCS_EVENT_QUERY_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
RCS_EVENT_QUERY_URI_PATH);
}
+
+ /**
+ * Allows RCS specific canonical address handling.
+ */
+ interface RcsCanonicalAddressHelper {
+ /**
+ * Returns the canonical address ID for a canonical address, if now row exists, this
+ * will add a row and return its ID. This helper works against the same table used by
+ * the SMS and MMS threads, but is accessible only by the phone process for use by RCS
+ * message storage.
+ *
+ * @throws IllegalArgumentException if unable to retrieve or create the canonical
+ * address entry.
+ */
+ static long getOrCreateCanonicalAddressId(
+ ContentResolver contentResolver, String canonicalAddress) {
+
+ Uri.Builder uriBuilder = CONTENT_AND_AUTHORITY.buildUpon();
+ uriBuilder.appendPath("canonical-address");
+ uriBuilder.appendQueryParameter("address", canonicalAddress);
+ Uri uri = uriBuilder.build();
+
+ try (Cursor cursor = contentResolver.query(uri, null, null, null)) {
+ if (cursor != null && cursor.moveToFirst()) {
+ return cursor.getLong(cursor.getColumnIndex(CanonicalAddressesColumns._ID));
+ } else {
+ Rlog.e(TAG, "getOrCreateCanonicalAddressId returned no rows");
+ }
+ }
+
+ Rlog.e(TAG, "getOrCreateCanonicalAddressId failed");
+ throw new IllegalArgumentException(
+ "Unable to find or allocate a canonical address ID");
+ }
+ }
}
/**
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index 9c64cf6ddd8f..75165afe097e 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -54,8 +54,15 @@ public final class AccessNetworkConstants {
*/
@SystemApi
public static final class TransportType {
+ /**
+ * Invalid transport type.
+ * @hide
+ */
+ public static final int INVALID = -1;
+
/** Wireless Wide Area Networks (i.e. Cellular) */
public static final int WWAN = 1;
+
/** Wireless Local Area Networks (i.e. Wifi) */
public static final int WLAN = 2;
@@ -65,6 +72,7 @@ public final class AccessNetworkConstants {
/** @hide */
public static String toString(int type) {
switch (type) {
+ case INVALID: return "INVALID";
case WWAN: return "WWAN";
case WLAN: return "WLAN";
default: return Integer.toString(type);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 068b68eeb73b..1b7228ae9a33 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2424,6 +2424,14 @@ public class CarrierConfigManager {
"5g_icon_configuration_string";
/**
+ * Support ASCII 7-BIT encoding for long SMS. This carrier config is used to enable
+ * this feature.
+ * @hide
+ */
+ public static final String KEY_ASCII_7_BIT_SUPPORT_FOR_LONG_MESSAGE_BOOL =
+ "ascii_7_bit_support_for_long_message_bool";
+
+ /**
* Controls RSRP threshold at which OpportunisticNetworkService will decide whether
* the opportunistic network is good enough for internet data.
*/
@@ -2589,6 +2597,16 @@ public class CarrierConfigManager {
}
}
+ /**
+ * An int array containing CDMA enhanced roaming indicator values for Home (non-roaming) network.
+ * The default values come from 3GPP2 C.R1001 table 8.1-1.
+ * Enhanced Roaming Indicator Number Assignments
+ *
+ * @hide
+ */
+ public static final String KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY =
+ "cdma_enhanced_roaming_indicator_for_home_network_int_array";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -2951,6 +2969,7 @@ public class CarrierConfigManager {
sDefaults.putInt(KEY_CALL_WAITING_SERVICE_CLASS_INT, 1 /* SERVICE_CLASS_VOICE */);
sDefaults.putString(KEY_5G_ICON_CONFIGURATION_STRING,
"connected_mmwave:None,connected:5G,not_restricted:None,restricted:None");
+ sDefaults.putBoolean(KEY_ASCII_7_BIT_SUPPORT_FOR_LONG_MESSAGE_BOOL, false);
/* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_GOOD */
sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT, -108);
/* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_MODERATE */
@@ -2966,6 +2985,10 @@ public class CarrierConfigManager {
/* Default value is 10 seconds. */
sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG, 10000);
sDefaults.putAll(Gps.getDefaults());
+ sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY,
+ new int[] {
+ 1 /* Roaming Indicator Off */
+ });
}
/**
diff --git a/telephony/java/android/telephony/CarrierRestrictionRules.java b/telephony/java/android/telephony/CarrierRestrictionRules.java
index 37847aef9167..d47b55ca4372 100644
--- a/telephony/java/android/telephony/CarrierRestrictionRules.java
+++ b/telephony/java/android/telephony/CarrierRestrictionRules.java
@@ -27,6 +27,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* Contains the list of carrier restrictions.
@@ -93,6 +94,9 @@ public final class CarrierRestrictionRules implements Parcelable {
value = {CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED, CARRIER_RESTRICTION_DEFAULT_ALLOWED})
public @interface CarrierRestrictionDefault {}
+ /* Wild character for comparison */
+ private static final char WILD_CHARACTER = '?';
+
private List<CarrierIdentifier> mAllowedCarriers;
private List<CarrierIdentifier> mExcludedCarriers;
@CarrierRestrictionDefault
@@ -166,6 +170,124 @@ public final class CarrierRestrictionRules implements Parcelable {
}
/**
+ * Tests an array of carriers with the carrier restriction configuration. The list of carrier
+ * ids passed as argument does not need to be the same as currently present in the device.
+ *
+ * @param carrierIds list of {@link CarrierIdentifier}, one for each SIM slot on the device
+ * @return a list of boolean with the same size as input, indicating if each
+ * {@link CarrierIdentifier} is allowed or not.
+ */
+ public List<Boolean> isCarrierIdentifiersAllowed(@NonNull List<CarrierIdentifier> carrierIds) {
+ ArrayList<Boolean> result = new ArrayList<>(carrierIds.size());
+
+ // First calculate the result for each slot independently
+ for (int i = 0; i < carrierIds.size(); i++) {
+ boolean inAllowedList = isCarrierIdInList(carrierIds.get(i), mAllowedCarriers);
+ boolean inExcludedList = isCarrierIdInList(carrierIds.get(i), mExcludedCarriers);
+ if (mCarrierRestrictionDefault == CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED) {
+ result.add((inAllowedList && !inExcludedList) ? true : false);
+ } else {
+ result.add((inExcludedList && !inAllowedList) ? false : true);
+ }
+ }
+ // Apply the multi-slot policy, if needed.
+ if (mMultiSimPolicy == MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT) {
+ for (boolean b : result) {
+ if (b) {
+ result.replaceAll(x -> true);
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Indicates if a certain carrier {@code id} is present inside a {@code list}
+ *
+ * @return true if the carrier {@code id} is present, false otherwise
+ */
+ private static boolean isCarrierIdInList(CarrierIdentifier id, List<CarrierIdentifier> list) {
+ for (CarrierIdentifier listItem : list) {
+ // Compare MCC and MNC
+ if (!patternMatch(id.getMcc(), listItem.getMcc())
+ || !patternMatch(id.getMnc(), listItem.getMnc())) {
+ continue;
+ }
+
+ // Compare SPN. Comparison is on the complete strings, case insensitive and with wild
+ // characters.
+ String listItemValue = convertNullToEmpty(listItem.getSpn());
+ String idValue = convertNullToEmpty(id.getSpn());
+ if (!listItemValue.isEmpty()) {
+ if (!patternMatch(idValue, listItemValue)) {
+ continue;
+ }
+ }
+
+ // The IMSI of the configuration can be shorter than actual IMSI in the SIM card.
+ listItemValue = convertNullToEmpty(listItem.getImsi());
+ idValue = convertNullToEmpty(id.getImsi());
+ if (!patternMatch(
+ idValue.substring(0, Math.min(idValue.length(), listItemValue.length())),
+ listItemValue)) {
+ continue;
+ }
+
+ // The GID1 of the configuration can be shorter than actual GID1 in the SIM card.
+ listItemValue = convertNullToEmpty(listItem.getGid1());
+ idValue = convertNullToEmpty(id.getGid1());
+ if (!patternMatch(
+ idValue.substring(0, Math.min(idValue.length(), listItemValue.length())),
+ listItemValue)) {
+ continue;
+ }
+
+ // The GID2 of the configuration can be shorter than actual GID2 in the SIM card.
+ listItemValue = convertNullToEmpty(listItem.getGid2());
+ idValue = convertNullToEmpty(id.getGid2());
+ if (!patternMatch(
+ idValue.substring(0, Math.min(idValue.length(), listItemValue.length())),
+ listItemValue)) {
+ continue;
+ }
+
+ // Valid match was found in the list
+ return true;
+ }
+ return false;
+ }
+
+ private static String convertNullToEmpty(String value) {
+ return Objects.toString(value, "");
+ }
+
+ /**
+ * Performs a case insensitive string comparison against a given pattern. The character '?'
+ * is used in the pattern as wild character in the comparison. The string must have the same
+ * length as the pattern.
+ *
+ * @param str string to match
+ * @param pattern string containing the pattern
+ * @return true in case of match, false otherwise
+ */
+ private static boolean patternMatch(String str, String pattern) {
+ if (str.length() != pattern.length()) {
+ return false;
+ }
+ String lowerCaseStr = str.toLowerCase();
+ String lowerCasePattern = pattern.toLowerCase();
+
+ for (int i = 0; i < lowerCasePattern.length(); i++) {
+ if (lowerCasePattern.charAt(i) != lowerCaseStr.charAt(i)
+ && lowerCasePattern.charAt(i) != WILD_CHARACTER) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
* {@link Parcelable#writeToParcel}
*/
@Override
diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java
index 6b1b84cd3458..856f08107fd7 100644
--- a/telephony/java/android/telephony/CellIdentityNr.java
+++ b/telephony/java/android/telephony/CellIdentityNr.java
@@ -30,6 +30,7 @@ public final class CellIdentityNr extends CellIdentity {
private final int mNrArfcn;
private final int mPci;
private final int mTac;
+ private final long mNci;
/**
*
@@ -44,11 +45,12 @@ public final class CellIdentityNr extends CellIdentity {
* @hide
*/
public CellIdentityNr(int pci, int tac, int nrArfcn, String mccStr, String mncStr,
- String alphal, String alphas) {
+ long nci, String alphal, String alphas) {
super(TAG, CellInfo.TYPE_NR, mccStr, mncStr, alphal, alphas);
mPci = pci;
mTac = tac;
mNrArfcn = nrArfcn;
+ mNci = nci;
}
/**
@@ -62,7 +64,7 @@ public final class CellIdentityNr extends CellIdentity {
@Override
public int hashCode() {
- return Objects.hash(super.hashCode(), mPci, mTac, mNrArfcn);
+ return Objects.hash(super.hashCode(), mPci, mTac, mNrArfcn, mNci);
}
@Override
@@ -72,7 +74,17 @@ public final class CellIdentityNr extends CellIdentity {
}
CellIdentityNr o = (CellIdentityNr) other;
- return super.equals(o) && mPci == o.mPci && mTac == o.mTac && mNrArfcn == o.mNrArfcn;
+ return super.equals(o) && mPci == o.mPci && mTac == o.mTac && mNrArfcn == o.mNrArfcn
+ && mNci == o.mNci;
+ }
+
+ /**
+ * Get the NR Cell Identity.
+ *
+ * @return The NR Cell Identity in range [0, 68719476735] or Long.MAX_VALUE if unknown.
+ */
+ public long getNci() {
+ return mNci;
}
/**
@@ -122,6 +134,7 @@ public final class CellIdentityNr extends CellIdentity {
.append(" mNrArfcn = ").append(mNrArfcn)
.append(" mMcc = ").append(mMccStr)
.append(" mMnc = ").append(mMncStr)
+ .append(" mNci = ").append(mNci)
.append(" mAlphaLong = ").append(mAlphaLong)
.append(" mAlphaShort = ").append(mAlphaShort)
.append(" }")
@@ -134,6 +147,7 @@ public final class CellIdentityNr extends CellIdentity {
dest.writeInt(mPci);
dest.writeInt(mTac);
dest.writeInt(mNrArfcn);
+ dest.writeLong(mNci);
}
/** Construct from Parcel, type has already been processed */
@@ -142,6 +156,7 @@ public final class CellIdentityNr extends CellIdentity {
mPci = in.readInt();
mTac = in.readInt();
mNrArfcn = in.readInt();
+ mNci = in.readLong();
}
/** Implement the Parcelable interface */
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index 38143335dbf1..dba437a3a007 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -141,6 +141,14 @@ public final class CellIdentityTdscdma extends CellIdentity {
return mCpid;
}
+ /**
+ * @return 16-bit UMTS Absolute RF Channel Number,
+ * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable.
+ */
+ public int getUarfcn() {
+ return mUarfcn;
+ }
+
/** @hide */
@Override
public int getChannelNumber() {
diff --git a/telephony/java/android/telephony/LocationAccessPolicy.java b/telephony/java/android/telephony/LocationAccessPolicy.java
index 53d69f447a56..24db438580c9 100644
--- a/telephony/java/android/telephony/LocationAccessPolicy.java
+++ b/telephony/java/android/telephony/LocationAccessPolicy.java
@@ -26,11 +26,12 @@ import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.location.LocationManager;
import android.os.Binder;
+import android.os.Build;
import android.os.Process;
-import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
+import android.widget.Toast;
import java.util.List;
@@ -41,61 +42,236 @@ import java.util.List;
public final class LocationAccessPolicy {
private static final String TAG = "LocationAccessPolicy";
private static final boolean DBG = false;
+ public static final int MAX_SDK_FOR_ANY_ENFORCEMENT = Build.VERSION_CODES.P;
- /**
- * API to determine if the caller has permissions to get cell location.
- *
- * @param pkgName Package name of the application requesting access
- * @param uid The uid of the package
- * @param pid The pid of the package
- * @param throwOnDeniedPermission Whether to throw if the location permission is denied.
- * @return boolean true or false if permissions is granted
- */
- public static boolean canAccessCellLocation(@NonNull Context context, @NonNull String pkgName,
- int uid, int pid, boolean throwOnDeniedPermission) throws SecurityException {
- Trace.beginSection("TelephonyLocationCheck");
- try {
- // Always allow the phone process and system server to access location. This avoid
- // breaking legacy code that rely on public-facing APIs to access cell location, and
- // it doesn't create an info leak risk because the cell location is stored in the phone
- // process anyway, and the system server already has location access.
- if (uid == Process.PHONE_UID || uid == Process.SYSTEM_UID || uid == Process.ROOT_UID) {
- return true;
+ public enum LocationPermissionResult {
+ ALLOWED,
+ /**
+ * Indicates that the denial is due to a transient device state
+ * (e.g. app-ops, location master switch)
+ */
+ DENIED_SOFT,
+ /**
+ * Indicates that the denial is due to a misconfigured app (e.g. missing entry in manifest)
+ */
+ DENIED_HARD,
+ }
+
+ public static class LocationPermissionQuery {
+ public final String callingPackage;
+ public final int callingUid;
+ public final int callingPid;
+ public final int minSdkVersionForCoarse;
+ public final int minSdkVersionForFine;
+ public final String method;
+
+ private LocationPermissionQuery(String callingPackage, int callingUid, int callingPid,
+ int minSdkVersionForCoarse, int minSdkVersionForFine, String method) {
+ this.callingPackage = callingPackage;
+ this.callingUid = callingUid;
+ this.callingPid = callingPid;
+ this.minSdkVersionForCoarse = minSdkVersionForCoarse;
+ this.minSdkVersionForFine = minSdkVersionForFine;
+ this.method = method;
+ }
+
+ public static class Builder {
+ private String mCallingPackage;
+ private int mCallingUid;
+ private int mCallingPid;
+ private int mMinSdkVersionForCoarse = Integer.MAX_VALUE;
+ private int mMinSdkVersionForFine = Integer.MAX_VALUE;
+ private String mMethod;
+
+ /**
+ * Mandatory parameter, used for performing permission checks.
+ */
+ public Builder setCallingPackage(String callingPackage) {
+ mCallingPackage = callingPackage;
+ return this;
}
- // We always require the location permission and also require the
- // location mode to be on for non-legacy apps. Legacy apps are
- // required to be in the foreground to at least mitigate the case
- // where a legacy app the user is not using tracks their location.
- // Granting ACCESS_FINE_LOCATION to an app automatically grants it
- // ACCESS_COARSE_LOCATION.
- if (throwOnDeniedPermission) {
- context.enforcePermission(Manifest.permission.ACCESS_COARSE_LOCATION,
- pid, uid, "canAccessCellLocation");
- } else if (context.checkPermission(Manifest.permission.ACCESS_COARSE_LOCATION,
- pid, uid) == PackageManager.PERMISSION_DENIED) {
- if (DBG) Log.w(TAG, "Permission checked failed (" + pid + "," + uid + ")");
- return false;
+ /**
+ * Mandatory parameter, used for performing permission checks.
+ */
+ public Builder setCallingUid(int callingUid) {
+ mCallingUid = callingUid;
+ return this;
}
- final int opCode = AppOpsManager.permissionToOpCode(
- Manifest.permission.ACCESS_COARSE_LOCATION);
- if (opCode != AppOpsManager.OP_NONE && context.getSystemService(AppOpsManager.class)
- .noteOpNoThrow(opCode, uid, pkgName) != AppOpsManager.MODE_ALLOWED) {
- if (DBG) Log.w(TAG, "AppOp check failed (" + uid + "," + pkgName + ")");
- return false;
+
+ /**
+ * Mandatory parameter, used for performing permission checks.
+ */
+ public Builder setCallingPid(int callingPid) {
+ mCallingPid = callingPid;
+ return this;
}
- if (!isLocationModeEnabled(context, UserHandle.getUserId(uid))) {
- if (DBG) Log.w(TAG, "Location disabled, failed, (" + uid + ")");
- return false;
+
+ /**
+ * Apps that target at least this sdk version will be checked for coarse location
+ * permission. Defaults to INT_MAX (which means don't check)
+ */
+ public Builder setMinSdkVersionForCoarse(
+ int minSdkVersionForCoarse) {
+ mMinSdkVersionForCoarse = minSdkVersionForCoarse;
+ return this;
}
- // If the user or profile is current, permission is granted.
- // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission.
- return isCurrentProfile(context, uid) || checkInteractAcrossUsersFull(context);
- } finally {
- Trace.endSection();
+
+ /**
+ * Apps that target at least this sdk version will be checked for fine location
+ * permission. Defaults to INT_MAX (which means don't check)
+ */
+ public Builder setMinSdkVersionForFine(
+ int minSdkVersionForFine) {
+ mMinSdkVersionForFine = minSdkVersionForFine;
+ return this;
+ }
+
+ /**
+ * Optional, for logging purposes only.
+ */
+ public Builder setMethod(String method) {
+ mMethod = method;
+ return this;
+ }
+
+ public LocationPermissionQuery build() {
+ return new LocationPermissionQuery(mCallingPackage, mCallingUid,
+ mCallingPid, mMinSdkVersionForCoarse, mMinSdkVersionForFine, mMethod);
+ }
+ }
+ }
+
+ private static void logError(Context context, String errorMsg) {
+ Log.e(TAG, errorMsg);
+ try {
+ if (Build.IS_DEBUGGABLE) {
+ Toast.makeText(context, errorMsg, Toast.LENGTH_SHORT).show();
+ }
+ } catch (Throwable t) {
+ // whatever, not important
+ }
+ }
+
+ private static LocationPermissionResult appOpsModeToPermissionResult(int appOpsMode) {
+ switch (appOpsMode) {
+ case AppOpsManager.MODE_ALLOWED:
+ return LocationPermissionResult.ALLOWED;
+ case AppOpsManager.MODE_ERRORED:
+ return LocationPermissionResult.DENIED_HARD;
+ default:
+ return LocationPermissionResult.DENIED_SOFT;
}
}
+ private static LocationPermissionResult checkAppLocationPermissionHelper(Context context,
+ LocationPermissionQuery query, String permissionToCheck) {
+ String locationTypeForLog =
+ Manifest.permission.ACCESS_FINE_LOCATION.equals(permissionToCheck)
+ ? "fine" : "coarse";
+
+ // Do the app-ops and the manifest check without any of the allow-overrides first.
+ boolean hasManifestPermission = checkManifestPermission(context, query.callingPid,
+ query.callingUid, permissionToCheck);
+
+ int appOpMode = context.getSystemService(AppOpsManager.class)
+ .noteOpNoThrow(AppOpsManager.permissionToOpCode(permissionToCheck),
+ query.callingUid, query.callingPackage);
+
+ if (hasManifestPermission && appOpMode == AppOpsManager.MODE_ALLOWED) {
+ // If the app did everything right, return without logging.
+ return LocationPermissionResult.ALLOWED;
+ }
+
+ // If the app has the manifest permission but not the app-op permission, it means that
+ // it's aware of the requirement and the user denied permission explicitly. If we see
+ // this, don't let any of the overrides happen.
+ if (hasManifestPermission) {
+ Log.i(TAG, query.callingPackage + " is aware of " + locationTypeForLog + " but the"
+ + " app-ops permission is specifically denied.");
+ return appOpsModeToPermissionResult(appOpMode);
+ }
+
+ int minSdkVersion = Manifest.permission.ACCESS_FINE_LOCATION.equals(permissionToCheck)
+ ? query.minSdkVersionForFine : query.minSdkVersionForCoarse;
+
+ // If the app fails for some reason, see if it should be allowed to proceed.
+ if (minSdkVersion > MAX_SDK_FOR_ANY_ENFORCEMENT) {
+ String errorMsg = "Allowing " + query.callingPackage + " " + locationTypeForLog
+ + " because we're not enforcing API " + query.minSdkVersionForFine + " yet."
+ + " Please fix this app because it will break in the future. Called from "
+ + query.method;
+ logError(context, errorMsg);
+ return null;
+ } else if (!isAppAtLeastSdkVersion(context, query.callingPackage, minSdkVersion)) {
+ String errorMsg = "Allowing " + query.callingPackage + " " + locationTypeForLog
+ + " because it doesn't target API " + query.minSdkVersionForFine + " yet."
+ + " Please fix this app. Called from " + query.method;
+ logError(context, errorMsg);
+ return null;
+ } else {
+ // If we're not allowing it due to the above two conditions, this means that the app
+ // did not declare the permission in their manifest.
+ return LocationPermissionResult.DENIED_HARD;
+ }
+ }
+
+ public static LocationPermissionResult checkLocationPermission(
+ Context context, LocationPermissionQuery query) {
+ // Always allow the phone process and system server to access location. This avoid
+ // breaking legacy code that rely on public-facing APIs to access cell location, and
+ // it doesn't create an info leak risk because the cell location is stored in the phone
+ // process anyway, and the system server already has location access.
+ if (query.callingUid == Process.PHONE_UID || query.callingUid == Process.SYSTEM_UID
+ || query.callingUid == Process.ROOT_UID) {
+ return LocationPermissionResult.ALLOWED;
+ }
+
+ // Check the system-wide requirements. If the location master switch is off or
+ // the app's profile isn't in foreground, return a soft denial.
+ if (!checkSystemLocationAccess(context, query.callingUid, query.callingPid)) {
+ return LocationPermissionResult.DENIED_SOFT;
+ }
+
+ // Do the check for fine, then for coarse.
+ if (query.minSdkVersionForFine < Integer.MAX_VALUE) {
+ LocationPermissionResult resultForFine = checkAppLocationPermissionHelper(
+ context, query, Manifest.permission.ACCESS_FINE_LOCATION);
+ if (resultForFine != null) {
+ return resultForFine;
+ }
+ }
+
+ if (query.minSdkVersionForCoarse < Integer.MAX_VALUE) {
+ LocationPermissionResult resultForCoarse = checkAppLocationPermissionHelper(
+ context, query, Manifest.permission.ACCESS_COARSE_LOCATION);
+ if (resultForCoarse != null) {
+ return resultForCoarse;
+ }
+ }
+
+ // At this point, we're out of location checks to do. If the app bypassed all the previous
+ // ones due to the SDK grandfathering schemes, allow it access.
+ return LocationPermissionResult.ALLOWED;
+ }
+
+
+ private static boolean checkManifestPermission(Context context, int pid, int uid,
+ String permissionToCheck) {
+ return context.checkPermission(permissionToCheck, pid, uid)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ private static boolean checkSystemLocationAccess(@NonNull Context context, int uid, int pid) {
+ if (!isLocationModeEnabled(context, UserHandle.getUserId(uid))) {
+ if (DBG) Log.w(TAG, "Location disabled, failed, (" + uid + ")");
+ return false;
+ }
+ // If the user or profile is current, permission is granted.
+ // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission.
+ return isCurrentProfile(context, uid) || checkInteractAcrossUsersFull(context, uid, pid);
+ }
+
private static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) {
LocationManager locationManager = context.getSystemService(LocationManager.class);
if (locationManager == null) {
@@ -105,10 +281,10 @@ public final class LocationAccessPolicy {
return locationManager.isLocationEnabledForUser(UserHandle.of(userId));
}
- private static boolean checkInteractAcrossUsersFull(@NonNull Context context) {
- return context.checkCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
- == PackageManager.PERMISSION_GRANTED;
+ private static boolean checkInteractAcrossUsersFull(
+ @NonNull Context context, int pid, int uid) {
+ return checkManifestPermission(context, pid, uid,
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL);
}
private static boolean isCurrentProfile(@NonNull Context context, int uid) {
@@ -132,4 +308,18 @@ public final class LocationAccessPolicy {
Binder.restoreCallingIdentity(token);
}
}
-}
+
+ private static boolean isAppAtLeastSdkVersion(Context context, String pkgName, int sdkVersion) {
+ try {
+ if (context.getPackageManager().getApplicationInfo(pkgName, 0).targetSdkVersion
+ >= sdkVersion) {
+ return true;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // In case of exception, assume known app (more strict checking)
+ // Note: This case will never happen since checkPackage is
+ // called to verify validity before checking app's version.
+ }
+ return false;
+ }
+} \ No newline at end of file
diff --git a/telephony/java/android/telephony/NetworkRegistrationState.java b/telephony/java/android/telephony/NetworkRegistrationState.java
index ceb76b57ae0c..6e6d59e62148 100644
--- a/telephony/java/android/telephony/NetworkRegistrationState.java
+++ b/telephony/java/android/telephony/NetworkRegistrationState.java
@@ -27,6 +27,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.Objects;
+import java.util.stream.Collectors;
/**
* Description of a mobile network registration state
@@ -151,7 +152,7 @@ public class NetworkRegistrationState implements Parcelable {
private final int[] mAvailableServices;
@Nullable
- private final CellIdentity mCellIdentity;
+ private CellIdentity mCellIdentity;
@Nullable
private VoiceSpecificRegistrationStates mVoiceSpecificStates;
@@ -360,7 +361,34 @@ public class NetworkRegistrationState implements Parcelable {
return 0;
}
- private static String regStateToString(int regState) {
+ /**
+ * Convert service type to string
+ *
+ * @hide
+ *
+ * @param serviceType The service type
+ * @return The service type in string format
+ */
+ public static String serviceTypeToString(@ServiceType int serviceType) {
+ switch (serviceType) {
+ case SERVICE_TYPE_VOICE: return "VOICE";
+ case SERVICE_TYPE_DATA: return "DATA";
+ case SERVICE_TYPE_SMS: return "SMS";
+ case SERVICE_TYPE_VIDEO: return "VIDEO";
+ case SERVICE_TYPE_EMERGENCY: return "EMERGENCY";
+ }
+ return "Unknown service type " + serviceType;
+ }
+
+ /**
+ * Convert registration state to string
+ *
+ * @hide
+ *
+ * @param regState The registration state
+ * @return The reg state in string
+ */
+ public static String regStateToString(@RegState int regState) {
switch (regState) {
case REG_STATE_NOT_REG_NOT_SEARCHING: return "NOT_REG_NOT_SEARCHING";
case REG_STATE_HOME: return "HOME";
@@ -389,14 +417,17 @@ public class NetworkRegistrationState implements Parcelable {
public String toString() {
return new StringBuilder("NetworkRegistrationState{")
.append(" domain=").append((mDomain == DOMAIN_CS) ? "CS" : "PS")
- .append("transportType=").append(mTransportType)
+ .append(" transportType=").append(TransportType.toString(mTransportType))
.append(" regState=").append(regStateToString(mRegState))
- .append(" roamingType=").append(mRoamingType)
+ .append(" roamingType=").append(ServiceState.roamingTypeToString(mRoamingType))
.append(" accessNetworkTechnology=")
.append(TelephonyManager.getNetworkTypeName(mAccessNetworkTechnology))
.append(" rejectCause=").append(mRejectCause)
.append(" emergencyEnabled=").append(mEmergencyOnly)
- .append(" supportedServices=").append(mAvailableServices)
+ .append(" availableServices=").append("[" + (mAvailableServices != null
+ ? Arrays.stream(mAvailableServices)
+ .mapToObj(type -> serviceTypeToString(type))
+ .collect(Collectors.joining(",")) : null) + "]")
.append(" cellIdentity=").append(mCellIdentity)
.append(" voiceSpecificStates=").append(mVoiceSpecificStates)
.append(" dataSpecificStates=").append(mDataSpecificStates)
@@ -490,4 +521,22 @@ public class NetworkRegistrationState implements Parcelable {
return new NetworkRegistrationState[size];
}
};
+
+ /**
+ * @hide
+ */
+ public NetworkRegistrationState sanitizeLocationInfo() {
+ NetworkRegistrationState result = copy();
+ result.mCellIdentity = null;
+ return result;
+ }
+
+ private NetworkRegistrationState copy() {
+ Parcel p = Parcel.obtain();
+ this.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ NetworkRegistrationState result = new NetworkRegistrationState(p);
+ p.recycle();
+ return result;
+ }
}
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index fea1b7b08a20..3ce646cb400b 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -45,7 +45,8 @@ import java.util.concurrent.Executor;
* <p>
* Override the methods for the state that you wish to receive updates for, and
* pass your PhoneStateListener object, along with bitwise-or of the LISTEN_
- * flags to {@link TelephonyManager#listen TelephonyManager.listen()}.
+ * flags to {@link TelephonyManager#listen TelephonyManager.listen()}. Methods are
+ * called when the state changes, as well as once on initial registration.
* <p>
* Note that access to some telephony information is
* permission-protected. Your application won't receive updates for protected
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 33178766f3a3..a1aee6d8217f 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -36,6 +36,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+import java.util.stream.Collectors;
/**
* Contains phone state and service related information.
@@ -887,6 +888,24 @@ public class ServiceState implements Parcelable {
}
/**
+ * Convert roaming type to string
+ *
+ * @param roamingType roaming type
+ * @return The roaming type in string format
+ *
+ * @hide
+ */
+ public static String roamingTypeToString(@RoamingType int roamingType) {
+ switch (roamingType) {
+ case ROAMING_TYPE_NOT_ROAMING: return "NOT_ROAMING";
+ case ROAMING_TYPE_UNKNOWN: return "UNKNOWN";
+ case ROAMING_TYPE_DOMESTIC: return "DOMESTIC";
+ case ROAMING_TYPE_INTERNATIONAL: return "INTERNATIONAL";
+ }
+ return "Unknown roaming type " + roamingType;
+ }
+
+ /**
* Convert radio technology to String
*
* @param rt radioTechnology
@@ -1867,4 +1886,29 @@ public class ServiceState implements Parcelable {
? range1
: range2;
}
+
+ /**
+ * Returns a copy of self with location-identifying information removed.
+ * Always clears the NetworkRegistrationState's CellIdentity fields, but if removeCoarseLocation
+ * is true, clears other info as well.
+ * @hide
+ */
+ public ServiceState sanitizeLocationInfo(boolean removeCoarseLocation) {
+ ServiceState state = new ServiceState(this);
+ if (state.mNetworkRegistrationStates != null) {
+ state.mNetworkRegistrationStates = state.mNetworkRegistrationStates.stream()
+ .map(NetworkRegistrationState::sanitizeLocationInfo)
+ .collect(Collectors.toList());
+ }
+ if (!removeCoarseLocation) return state;
+
+ state.mDataOperatorAlphaLong = null;
+ state.mDataOperatorAlphaShort = null;
+ state.mDataOperatorNumeric = null;
+ state.mVoiceOperatorAlphaLong = null;
+ state.mVoiceOperatorAlphaShort = null;
+ state.mVoiceOperatorNumeric = null;
+
+ return state;
+ }
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 313146d5538b..836a50bf05c7 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -59,6 +59,7 @@ import android.util.DisplayMetrics;
import android.util.Log;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
+import com.android.internal.telephony.ISetOpportunisticDataCallback;
import com.android.internal.telephony.ISub;
import com.android.internal.telephony.ITelephonyRegistry;
import com.android.internal.telephony.PhoneConstants;
@@ -72,6 +73,7 @@ import java.util.List;
import java.util.Locale;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
@@ -864,7 +866,8 @@ public class SubscriptionManager {
}
/**
- * Callback invoked when there is any change to any SubscriptionInfo. Typically
+ * Callback invoked when there is any change to any SubscriptionInfo, as well as once on
+ * registering for changes with {@link #addOnSubscriptionsChangedListener}. Typically
* this method would invoke {@link #getActiveSubscriptionInfoList}
*/
public void onSubscriptionsChanged() {
@@ -916,7 +919,9 @@ public class SubscriptionManager {
/**
* Register for changes to the list of active {@link SubscriptionInfo} records or to the
* individual records themselves. When a change occurs the onSubscriptionsChanged method of
- * the listener will be invoked immediately if there has been a notification.
+ * the listener will be invoked immediately if there has been a notification. The
+ * onSubscriptionChanged method will also be triggered once initially when calling this
+ * function.
*
* @param listener an instance of {@link OnSubscriptionsChangedListener} with
* onSubscriptionsChanged overridden.
@@ -1859,7 +1864,7 @@ public class SubscriptionManager {
iSub.setDefaultSmsSubId(subscriptionId);
}
} catch (RemoteException ex) {
- // ignore it
+ ex.rethrowFromSystemServer();
}
}
@@ -2573,17 +2578,35 @@ public class SubscriptionManager {
* {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}, it means
* it's unset and {@link SubscriptionManager#getDefaultDataSubscriptionId()}
* is used to determine which modem is preferred.
+ * @param needValidation whether validation is needed before switch happens.
+ * @param executor The executor of where the callback will execute.
+ * @param callback Callback will be triggered once it succeeds or failed.
+ * See {@link TelephonyManager.SetOpportunisticSubscriptionResult}
+ * for more details. Pass null if don't care about the result.
+ *
* @hide
*
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void setPreferredDataSubscriptionId(int subId) {
+ public void setPreferredDataSubscriptionId(int subId, boolean needValidation,
+ @NonNull @CallbackExecutor Executor executor, Consumer<Integer> callback) {
if (VDBG) logd("[setPreferredDataSubscriptionId]+ subId:" + subId);
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
- if (iSub != null) {
- iSub.setPreferredDataSubscriptionId(subId);
- }
+ if (iSub == null) return;
+
+ ISetOpportunisticDataCallback callbackStub = new ISetOpportunisticDataCallback.Stub() {
+ @Override
+ public void onComplete(int result) {
+ Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
+ if (callback != null) {
+ callback.accept(result);
+ }
+ }));
+ }
+ };
+ iSub.setPreferredDataSubscriptionId(subId, needValidation, callbackStub);
} catch (RemoteException ex) {
// ignore it
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f5d452e9721d..ced4f4ab6573 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -229,10 +229,19 @@ public class TelephonyManager {
public static final int SRVCC_STATE_HANDOVER_CANCELED = 3;
/**
- * An invalid UICC card identifier. See {@link #getCardIdForDefaultEuicc()} and
- * {@link UiccCardInfo#getCardId()}.
+ * A UICC card identifier used if the device does not support the operation.
+ * For example, {@link #getCardIdForDefaultEuicc()} returns this value if the device has no
+ * eUICC, or the eUICC cannot be read.
*/
- public static final int INVALID_CARD_ID = -1;
+ public static final int UNSUPPORTED_CARD_ID = -1;
+
+ /**
+ * A UICC card identifier used before the UICC card is loaded. See
+ * {@link #getCardIdForDefaultEuicc()} and {@link UiccCardInfo#getCardId()}.
+ * <p>
+ * Note that once the UICC card is loaded, the card ID may become {@link #UNSUPPORTED_CARD_ID}.
+ */
+ public static final int UNINITIALIZED_CARD_ID = -2;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -1689,10 +1698,7 @@ public class TelephonyManager {
* @deprecated use {@link #getAllCellInfo} instead, which returns a superset of this API.
*/
@Deprecated
- @RequiresPermission(anyOf = {
- android.Manifest.permission.ACCESS_COARSE_LOCATION,
- android.Manifest.permission.ACCESS_FINE_LOCATION
- })
+ @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
public CellLocation getCellLocation() {
try {
ITelephony telephony = getITelephony();
@@ -3178,24 +3184,25 @@ public class TelephonyManager {
}
/**
- * Get the card ID of the default eUICC card. If there is no eUICC, returns
- * {@link #INVALID_CARD_ID}.
+ * Get the card ID of the default eUICC card. If the eUICCs have not yet been loaded, returns
+ * {@link #UNINITIALIZED_CARD_ID}. If there is no eUICC or the device does not support card IDs
+ * for eUICCs, returns {@link #UNSUPPORTED_CARD_ID}.
*
* <p>The card ID is a unique identifier associated with a UICC or eUICC card. Card IDs are
* unique to a device, and always refer to the same UICC or eUICC card unless the device goes
* through a factory reset.
*
- * @return card ID of the default eUICC card.
+ * @return card ID of the default eUICC card, if loaded.
*/
public int getCardIdForDefaultEuicc() {
try {
ITelephony telephony = getITelephony();
if (telephony == null) {
- return INVALID_CARD_ID;
+ return UNINITIALIZED_CARD_ID;
}
return telephony.getCardIdForDefaultEuicc(mSubId, mContext.getOpPackageName());
} catch (RemoteException e) {
- return INVALID_CARD_ID;
+ return UNINITIALIZED_CARD_ID;
}
}
@@ -4941,7 +4948,7 @@ public class TelephonyManager {
* @return List of {@link android.telephony.CellInfo}; null if cell
* information is unavailable.
*/
- @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
+ @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
public List<CellInfo> getAllCellInfo() {
try {
ITelephony telephony = getITelephony();
@@ -5018,7 +5025,7 @@ public class TelephonyManager {
* @param executor the executor on which callback will be invoked.
* @param callback a callback to receive CellInfo.
*/
- @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
+ @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
public void requestCellInfoUpdate(
@NonNull @CallbackExecutor Executor executor, @NonNull CellInfoCallback callback) {
try {
@@ -5057,7 +5064,7 @@ public class TelephonyManager {
* @hide
*/
@SystemApi
- @RequiresPermission(allOf = {android.Manifest.permission.ACCESS_COARSE_LOCATION,
+ @RequiresPermission(allOf = {android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.MODIFY_PHONE_STATE})
public void requestCellInfoUpdate(@NonNull WorkSource workSource,
@NonNull @CallbackExecutor Executor executor, @NonNull CellInfoCallback callback) {
@@ -6647,9 +6654,10 @@ public class TelephonyManager {
*
* <p> Note that this scan can take a long time (sometimes minutes) to happen.
*
- * <p>Requires Permission:
+ * <p>Requires Permissions:
* {@link android.Manifest.permission#MODIFY_PHONE_STATE} or that the calling app has carrier
* privileges (see {@link #hasCarrierPrivileges})
+ * and {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
*
* @return {@link CellNetworkScanResult} with the status
* {@link CellNetworkScanResult#STATUS_SUCCESS} and a list of
@@ -6658,12 +6666,15 @@ public class TelephonyManager {
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ Manifest.permission.ACCESS_COARSE_LOCATION
+ })
public CellNetworkScanResult getAvailableNetworks() {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.getCellNetworkScanResults(getSubId());
+ return telephony.getCellNetworkScanResults(getSubId(), getOpPackageName());
}
} catch (RemoteException ex) {
Rlog.e(TAG, "getAvailableNetworks RemoteException", ex);
@@ -6682,7 +6693,8 @@ public class TelephonyManager {
*
* <p>Requires Permission:
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
- * app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * app has carrier privileges (see {@link #hasCarrierPrivileges})
+ * and {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
*
* @param request Contains all the RAT with bands/channels that need to be scanned.
* @param executor The executor through which the callback should be invoked. Since the scan
@@ -6693,7 +6705,10 @@ public class TelephonyManager {
* @return A NetworkScan obj which contains a callback which can be used to stop the scan.
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ })
public NetworkScan requestNetworkScan(
NetworkScanRequest request, Executor executor,
TelephonyScanManager.NetworkScanCallback callback) {
@@ -6702,7 +6717,8 @@ public class TelephonyManager {
mTelephonyScanManager = new TelephonyScanManager();
}
}
- return mTelephonyScanManager.requestNetworkScan(getSubId(), request, executor, callback);
+ return mTelephonyScanManager.requestNetworkScan(getSubId(), request, executor, callback,
+ getOpPackageName());
}
/**
@@ -6712,7 +6728,10 @@ public class TelephonyManager {
* @removed
*/
@Deprecated
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ })
public NetworkScan requestNetworkScan(
NetworkScanRequest request, TelephonyScanManager.NetworkScanCallback callback) {
return requestNetworkScan(request, AsyncTask.SERIAL_EXECUTOR, callback);
@@ -8713,10 +8732,14 @@ public class TelephonyManager {
* given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges})
+ * and {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @RequiresPermission(allOf = {
+ Manifest.permission.READ_PHONE_STATE,
+ Manifest.permission.ACCESS_COARSE_LOCATION
+ })
public ServiceState getServiceState() {
return getServiceStateForSubscriber(getSubId());
}
@@ -10094,6 +10117,29 @@ public class TelephonyManager {
return false;
}
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"SET_OPPORTUNISTIC_SUB"}, value = {
+ SET_OPPORTUNISTIC_SUB_SUCCESS,
+ SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED,
+ SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER})
+ public @interface SetOpportunisticSubscriptionResult {}
+
+ /**
+ * No error. Operation succeeded.
+ */
+ public static final int SET_OPPORTUNISTIC_SUB_SUCCESS = 0;
+
+ /**
+ * Validation failed when trying to switch to preferred subscription.
+ */
+ public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1;
+
+ /**
+ * The parameter passed in is invalid.
+ */
+ public static final int SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER = 2;
+
/**
* Set preferred opportunistic data subscription id.
*
@@ -10309,11 +10355,14 @@ public class TelephonyManager {
/**
* Get whether reboot is required or not after making changes to modem configurations.
- * @Return {@code True} if reboot is required after making changes to modem configurations,
- * otherwise return {@code False}.
+ * The modem configuration change refers to switching from single SIM configuration to DSDS
+ * or the other way around.
+ * @Return {@code true} if reboot is required after making changes to modem configurations,
+ * otherwise return {@code false}.
*
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isRebootRequiredForModemConfigChange() {
try {
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index 96ff33255b53..91f74b867fa0 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -29,14 +29,14 @@ import android.os.Messenger;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.util.Log;
import android.util.SparseArray;
+
+import com.android.internal.telephony.ITelephony;
+
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;
-import com.android.internal.telephony.ITelephony;
-
/**
* Manages the radio access network scan requests and callbacks.
*/
@@ -183,6 +183,7 @@ public final class TelephonyScanManager {
*
* <p>
* Requires Permission:
+ * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} and
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
* Or the calling app has carrier privileges. @see #hasCarrierPrivileges
*
@@ -192,11 +193,13 @@ public final class TelephonyScanManager {
* @hide
*/
public NetworkScan requestNetworkScan(int subId,
- NetworkScanRequest request, Executor executor, NetworkScanCallback callback) {
+ NetworkScanRequest request, Executor executor, NetworkScanCallback callback,
+ String callingPackage) {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- int scanId = telephony.requestNetworkScan(subId, request, mMessenger, new Binder());
+ int scanId = telephony.requestNetworkScan(
+ subId, request, mMessenger, new Binder(), callingPackage);
saveScanInfo(scanId, request, executor, callback);
return new NetworkScan(scanId, subId);
}
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 1bbf9f4c4d25..ad343498f9e1 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -460,7 +460,7 @@ public class EuiccManager {
*/
@Nullable
public String getEid() {
- if (!refreshCardIdIfInvalid()) {
+ if (!refreshCardIdIfUninitialized()) {
return null;
}
try {
@@ -483,7 +483,7 @@ public class EuiccManager {
@SystemApi
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public int getOtaStatus() {
- if (!refreshCardIdIfInvalid()) {
+ if (!refreshCardIdIfUninitialized()) {
return EUICC_OTA_STATUS_UNAVAILABLE;
}
try {
@@ -518,7 +518,7 @@ public class EuiccManager {
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void downloadSubscription(DownloadableSubscription subscription,
boolean switchAfterDownload, PendingIntent callbackIntent) {
- if (!refreshCardIdIfInvalid()) {
+ if (!refreshCardIdIfUninitialized()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -580,7 +580,7 @@ public class EuiccManager {
@SystemApi
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void continueOperation(Intent resolutionIntent, Bundle resolutionExtras) {
- if (!refreshCardIdIfInvalid()) {
+ if (!refreshCardIdIfUninitialized()) {
PendingIntent callbackIntent =
resolutionIntent.getParcelableExtra(
EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT);
@@ -617,7 +617,7 @@ public class EuiccManager {
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void getDownloadableSubscriptionMetadata(
DownloadableSubscription subscription, PendingIntent callbackIntent) {
- if (!refreshCardIdIfInvalid()) {
+ if (!refreshCardIdIfUninitialized()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -647,7 +647,7 @@ public class EuiccManager {
@SystemApi
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void getDefaultDownloadableSubscriptionList(PendingIntent callbackIntent) {
- if (!refreshCardIdIfInvalid()) {
+ if (!refreshCardIdIfUninitialized()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -666,7 +666,7 @@ public class EuiccManager {
*/
@Nullable
public EuiccInfo getEuiccInfo() {
- if (!refreshCardIdIfInvalid()) {
+ if (!refreshCardIdIfUninitialized()) {
return null;
}
try {
@@ -691,7 +691,7 @@ public class EuiccManager {
*/
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void deleteSubscription(int subscriptionId, PendingIntent callbackIntent) {
- if (!refreshCardIdIfInvalid()) {
+ if (!refreshCardIdIfUninitialized()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -731,7 +731,7 @@ public class EuiccManager {
*/
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void switchToSubscription(int subscriptionId, PendingIntent callbackIntent) {
- if (!refreshCardIdIfInvalid()) {
+ if (!refreshCardIdIfUninitialized()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -757,7 +757,7 @@ public class EuiccManager {
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void updateSubscriptionNickname(
int subscriptionId, String nickname, PendingIntent callbackIntent) {
- if (!refreshCardIdIfInvalid()) {
+ if (!refreshCardIdIfUninitialized()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -781,7 +781,7 @@ public class EuiccManager {
@SystemApi
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void eraseSubscriptions(PendingIntent callbackIntent) {
- if (!refreshCardIdIfInvalid()) {
+ if (!refreshCardIdIfUninitialized()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -811,7 +811,7 @@ public class EuiccManager {
* @hide
*/
public void retainSubscriptionsForFactoryReset(PendingIntent callbackIntent) {
- if (!refreshCardIdIfInvalid()) {
+ if (!refreshCardIdIfUninitialized()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -822,16 +822,24 @@ public class EuiccManager {
}
}
- private boolean refreshCardIdIfInvalid() {
- if (!isEnabled()) {
- return false;
- }
- // Refresh mCardId if it's invalid.
- if (mCardId == TelephonyManager.INVALID_CARD_ID) {
+ /**
+ * Refreshes the cardId if its uninitialized, and returns whether we should continue the
+ * operation.
+ * <p>
+ * Note that after a successful refresh, the mCardId may be TelephonyManager.UNSUPPORTED_CARD_ID
+ * on older HALs. For backwards compatability, we continue to the LPA and let it decide which
+ * card to use.
+ */
+ private boolean refreshCardIdIfUninitialized() {
+ // Refresh mCardId if its UNINITIALIZED_CARD_ID
+ if (mCardId == TelephonyManager.UNINITIALIZED_CARD_ID) {
TelephonyManager tm = (TelephonyManager)
mContext.getSystemService(Context.TELEPHONY_SERVICE);
mCardId = tm.getCardIdForDefaultEuicc();
}
+ if (mCardId == TelephonyManager.UNINITIALIZED_CARD_ID) {
+ return false;
+ }
return true;
}
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 59167b7d5bba..73f055649b3f 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -350,6 +350,9 @@ public final class ImsCallProfile implements Parcelable {
/** Indicates if the call is for testing purpose */
private boolean mEmergencyCallTesting = false;
+ /** Indicates if we have known the intent of the user for the call is emergency */
+ private boolean mHasKnownUserIntentEmergency = false;
+
/**
* Extras associated with this {@link ImsCallProfile}.
* <p>
@@ -789,12 +792,13 @@ public final class ImsCallProfile implements Parcelable {
*
* @hide
*/
- public void setEmergencyCallInfo(EmergencyNumber num) {
+ public void setEmergencyCallInfo(EmergencyNumber num, boolean hasKnownUserIntentEmergency) {
setEmergencyServiceCategories(num.getEmergencyServiceCategoryBitmaskInternalDial());
setEmergencyUrns(num.getEmergencyUrns());
setEmergencyCallRouting(num.getEmergencyCallRouting());
setEmergencyCallTesting(num.getEmergencyNumberSourceBitmask()
== EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST);
+ setHasKnownUserIntentEmergency(hasKnownUserIntentEmergency);
}
/**
@@ -860,6 +864,19 @@ public final class ImsCallProfile implements Parcelable {
}
/**
+ * Set if we have known the user intent of the call is emergency.
+ *
+ * This is only used to specify when the dialed number is ambiguous when it can be identified
+ * as both emergency number and any other non-emergency number; e.g. in some situation, 611
+ * could be both an emergency number in a country and a non-emergency number of a carrier's
+ * customer service hotline.
+ */
+ @VisibleForTesting
+ public void setHasKnownUserIntentEmergency(boolean hasKnownUserIntentEmergency) {
+ mHasKnownUserIntentEmergency = hasKnownUserIntentEmergency;
+ }
+
+ /**
* Get the emergency service categories, only valid if {@link #getServiceType} returns
* {@link #SERVICE_TYPE_EMERGENCY}
*
@@ -916,4 +933,16 @@ public final class ImsCallProfile implements Parcelable {
public boolean isEmergencyCallTesting() {
return mEmergencyCallTesting;
}
+
+ /**
+ * Checks if we have known the user intent of the call is emergency.
+ *
+ * This is only used to specify when the dialed number is ambiguous when it can be identified
+ * as both emergency number and any other non-emergency number; e.g. in some situation, 611
+ * could be both an emergency number in a country and a non-emergency number of a carrier's
+ * customer service hotline.
+ */
+ public boolean hasKnownUserIntentEmergency() {
+ return mHasKnownUserIntentEmergency;
+ }
}
diff --git a/telephony/java/android/telephony/ims/Rcs1To1Thread.java b/telephony/java/android/telephony/ims/Rcs1To1Thread.java
index 3255f8d0786d..d4a78ffb77db 100644
--- a/telephony/java/android/telephony/ims/Rcs1To1Thread.java
+++ b/telephony/java/android/telephony/ims/Rcs1To1Thread.java
@@ -22,8 +22,6 @@ import android.annotation.WorkerThread;
* Rcs1To1Thread represents a single RCS conversation thread with a total of two
* {@link RcsParticipant}s. Please see Section 5 (1-to-1 Messaging) - GSMA RCC.71 (RCS Universal
* Profile Service Definition Document)
- *
- * @hide - TODO: make public
*/
public class Rcs1To1Thread extends RcsThread {
private int mThreadId;
diff --git a/telephony/java/android/telephony/ims/RcsEvent.java b/telephony/java/android/telephony/ims/RcsEvent.java
index ef359a124d47..df62277f9ac1 100644
--- a/telephony/java/android/telephony/ims/RcsEvent.java
+++ b/telephony/java/android/telephony/ims/RcsEvent.java
@@ -19,8 +19,6 @@ import android.os.Parcel;
/**
* The base class for events that can happen on {@link RcsParticipant}s and {@link RcsThread}s.
- *
- * @hide - TODO: make public
*/
public abstract class RcsEvent {
/**
diff --git a/telephony/java/android/telephony/ims/RcsEventQueryParams.java b/telephony/java/android/telephony/ims/RcsEventQueryParams.java
index 5249becd476e..9dbfe4393213 100644
--- a/telephony/java/android/telephony/ims/RcsEventQueryParams.java
+++ b/telephony/java/android/telephony/ims/RcsEventQueryParams.java
@@ -37,8 +37,6 @@ import java.security.InvalidParameterException;
* The parameters to pass into
* {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} in order to select a
* subset of {@link RcsEvent}s present in the message store.
- *
- * @hide - TODO: make public
*/
public final class RcsEventQueryParams implements Parcelable {
/**
@@ -152,8 +150,8 @@ public final class RcsEventQueryParams implements Parcelable {
}
/**
- * @return Returns the type of {@link RcsEvent}s that this {@link RcsEventQueryParams} is
- * set to query for.
+ * @return Returns the number of {@link RcsEvent}s to be returned from the query. A value of
+ * 0 means there is no set limit.
*/
public int getLimit() {
return mLimit;
diff --git a/telephony/java/android/telephony/ims/RcsEventQueryResult.java b/telephony/java/android/telephony/ims/RcsEventQueryResult.java
index f8d57fa5c09d..c30e4ccd7aa2 100644
--- a/telephony/java/android/telephony/ims/RcsEventQueryResult.java
+++ b/telephony/java/android/telephony/ims/RcsEventQueryResult.java
@@ -25,8 +25,6 @@ import java.util.List;
* The result of a {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)}
* call. This class allows getting the token for querying the next batch of events in order to
* prevent handling large amounts of data at once.
- *
- * @hide - TODO: make public
*/
public final class RcsEventQueryResult implements Parcelable {
private RcsQueryContinuationToken mContinuationToken;
diff --git a/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.java b/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.java
index 663def5df50f..14af8ea63a67 100644
--- a/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.java
+++ b/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.java
@@ -24,8 +24,6 @@ import android.os.Parcelable;
* Pass an instance of this class to
* {@link RcsMessage#insertFileTransfer(RcsFileTransferCreationParams)} create an
* {@link RcsFileTransferPart} and save it into storage.
- *
- * @hide - TODO: make public
*/
public final class RcsFileTransferCreationParams implements Parcelable {
private String mRcsFileTransferSessionId;
diff --git a/telephony/java/android/telephony/ims/RcsFileTransferPart.java b/telephony/java/android/telephony/ims/RcsFileTransferPart.java
index 1ce799919e09..9531c2e2f981 100644
--- a/telephony/java/android/telephony/ims/RcsFileTransferPart.java
+++ b/telephony/java/android/telephony/ims/RcsFileTransferPart.java
@@ -26,8 +26,6 @@ import java.lang.annotation.RetentionPolicy;
/**
* A part of a composite {@link RcsMessage} that holds a file transfer. Please see Section 7
* (File Transfer) - GSMA RCC.71 (RCS Universal Profile Service Definition Document)
- *
- * @hide - TODO: make public
*/
public class RcsFileTransferPart {
/**
diff --git a/telephony/java/android/telephony/ims/RcsGroupThread.java b/telephony/java/android/telephony/ims/RcsGroupThread.java
index 2c42494ee924..6e17bc2a685f 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThread.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThread.java
@@ -29,8 +29,6 @@ import java.util.Set;
* RcsGroupThread represents a single RCS conversation thread where {@link RcsParticipant}s can join
* or leave. Please see Section 6 (Group Chat) - GSMA RCC.71 (RCS Universal Profile Service
* Definition Document)
- *
- * @hide - TODO: make public
*/
public class RcsGroupThread extends RcsThread {
/**
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java
index bc61877a81d6..609b1740a536 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java
@@ -20,8 +20,6 @@ import android.os.Parcel;
/**
* An event that happened on an {@link RcsGroupThread}.
- *
- * @hide - TODO: make public
*/
public abstract class RcsGroupThreadEvent extends RcsEvent {
private final int mRcsGroupThreadId;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java
index 74af9738e976..e768439d6cfa 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java
@@ -24,8 +24,6 @@ import android.os.Parcelable;
/**
* An event that indicates an {@link RcsGroupThread}'s icon was changed. Please see R6-2-5 - GSMA
* RCC.71 (RCS Universal Profile Service Definition Document)
- *
- * @hide - TODO: make public
*/
public final class RcsGroupThreadIconChangedEvent extends RcsGroupThreadEvent implements
Parcelable {
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java
index 06f4d5b10bb4..02030bc6a2ec 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java
@@ -23,8 +23,6 @@ import android.os.Parcelable;
/**
* An event that indicates an {@link RcsGroupThread}'s name was changed. Please see R6-2-5 - GSMA
* RCC.71 (RCS Universal Profile Service Definition Document)
- *
- * @hide - TODO: make public
*/
public final class RcsGroupThreadNameChangedEvent extends RcsGroupThreadEvent implements
Parcelable {
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java
index 493270795e01..0d1a5730f0a0 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java
@@ -22,8 +22,6 @@ import android.os.Parcelable;
/**
* An event that indicates an RCS participant has joined an {@link RcsThread}. Please see US6-3 -
* GSMA RCC.71 (RCS Universal Profile Service Definition Document)
- *
- * @hide - TODO: make public
*/
public final class RcsGroupThreadParticipantJoinedEvent extends RcsGroupThreadEvent implements
Parcelable {
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java
index 970a046e1105..cd525086749a 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java
@@ -22,8 +22,6 @@ import android.os.Parcelable;
/**
* An event that indicates an RCS participant has left an {@link RcsThread}. Please see US6-23 -
* GSMA RCC.71 (RCS Universal Profile Service Definition Document)
- *
- * @hide - TODO: make public
*/
public final class RcsGroupThreadParticipantLeftEvent extends RcsGroupThreadEvent implements
Parcelable {
diff --git a/telephony/java/android/telephony/ims/RcsIncomingMessage.java b/telephony/java/android/telephony/ims/RcsIncomingMessage.java
index f3b7815c2453..61911abd00c5 100644
--- a/telephony/java/android/telephony/ims/RcsIncomingMessage.java
+++ b/telephony/java/android/telephony/ims/RcsIncomingMessage.java
@@ -19,8 +19,6 @@ import android.annotation.WorkerThread;
/**
* This is a single instance of a message received over RCS.
- *
- * @hide - TODO: make public
*/
public class RcsIncomingMessage extends RcsMessage {
/**
diff --git a/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java b/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java
index 64b2339905eb..61dedbc1578a 100644
--- a/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java
+++ b/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java
@@ -24,8 +24,6 @@ import android.os.Parcelable;
* {@link RcsIncomingMessageCreationParams} is a collection of parameters that should be passed
* into {@link RcsThread#addIncomingMessage(RcsIncomingMessageCreationParams)} to generate an
* {@link RcsIncomingMessage} on that {@link RcsThread}
- *
- * @hide - TODO: make public
*/
public final class RcsIncomingMessageCreationParams extends RcsMessageCreationParams implements
Parcelable {
diff --git a/telephony/java/android/telephony/ims/RcsManager.java b/telephony/java/android/telephony/ims/RcsManager.java
index 90bd0446d6f3..22e4b2249c36 100644
--- a/telephony/java/android/telephony/ims/RcsManager.java
+++ b/telephony/java/android/telephony/ims/RcsManager.java
@@ -20,8 +20,6 @@ import android.content.Context;
/**
* The manager class for RCS related utilities.
- *
- * @hide - TODO: make public
*/
@SystemService(Context.TELEPHONY_RCS_SERVICE)
public class RcsManager {
diff --git a/telephony/java/android/telephony/ims/RcsMessage.java b/telephony/java/android/telephony/ims/RcsMessage.java
index 1700941b94ed..32274131a5ad 100644
--- a/telephony/java/android/telephony/ims/RcsMessage.java
+++ b/telephony/java/android/telephony/ims/RcsMessage.java
@@ -27,8 +27,6 @@ import java.util.Set;
/**
* This is a single instance of a message sent or received over RCS.
- *
- * @hide - TODO: make public
*/
public abstract class RcsMessage {
/**
diff --git a/telephony/java/android/telephony/ims/RcsMessageCreationParams.java b/telephony/java/android/telephony/ims/RcsMessageCreationParams.java
index 9ac4dcdf2d74..c46c605d861d 100644
--- a/telephony/java/android/telephony/ims/RcsMessageCreationParams.java
+++ b/telephony/java/android/telephony/ims/RcsMessageCreationParams.java
@@ -27,8 +27,6 @@ import android.os.Parcel;
* {@link RcsThread#addIncomingMessage(RcsIncomingMessageCreationParams)} and
* {@link RcsThread#addOutgoingMessage(RcsOutgoingMessageCreationParams)} to create and persist
* {@link RcsMessage}s on an {@link RcsThread}
- *
- * @hide - TODO: make public
*/
public class RcsMessageCreationParams {
// The globally unique id of the RcsMessage to be created.
diff --git a/telephony/java/android/telephony/ims/RcsMessageQueryParams.java b/telephony/java/android/telephony/ims/RcsMessageQueryParams.java
index fae0d97cd722..535a597f5e1e 100644
--- a/telephony/java/android/telephony/ims/RcsMessageQueryParams.java
+++ b/telephony/java/android/telephony/ims/RcsMessageQueryParams.java
@@ -31,8 +31,6 @@ import java.security.InvalidParameterException;
* The parameters to pass into
* {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)} in order to select a
* subset of {@link RcsMessage}s present in the message store.
- *
- * @hide - TODO: make public
*/
public final class RcsMessageQueryParams implements Parcelable {
/**
diff --git a/telephony/java/android/telephony/ims/RcsMessageQueryResult.java b/telephony/java/android/telephony/ims/RcsMessageQueryResult.java
index 5adab760d594..3514b48e80a1 100644
--- a/telephony/java/android/telephony/ims/RcsMessageQueryResult.java
+++ b/telephony/java/android/telephony/ims/RcsMessageQueryResult.java
@@ -32,8 +32,6 @@ import java.util.List;
* The result of a {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)}
* call. This class allows getting the token for querying the next batch of messages in order to
* prevent handling large amounts of data at once.
- *
- * @hide - TODO: make public
*/
public final class RcsMessageQueryResult implements Parcelable {
// The token to continue the query to get the next batch of results
diff --git a/telephony/java/android/telephony/ims/RcsMessageSnippet.java b/telephony/java/android/telephony/ims/RcsMessageSnippet.java
index 565bb99de89a..b0b930c56e91 100644
--- a/telephony/java/android/telephony/ims/RcsMessageSnippet.java
+++ b/telephony/java/android/telephony/ims/RcsMessageSnippet.java
@@ -23,8 +23,6 @@ import android.telephony.ims.RcsMessage.RcsMessageStatus;
/**
* An immutable summary of the latest {@link RcsMessage} on an {@link RcsThread}
- *
- * @hide - TODO: make public
*/
public final class RcsMessageSnippet implements Parcelable {
private final String mText;
diff --git a/telephony/java/android/telephony/ims/RcsMessageStore.java b/telephony/java/android/telephony/ims/RcsMessageStore.java
index eca5ed518521..d811c6e93a56 100644
--- a/telephony/java/android/telephony/ims/RcsMessageStore.java
+++ b/telephony/java/android/telephony/ims/RcsMessageStore.java
@@ -26,8 +26,6 @@ import java.util.List;
/**
* RcsMessageStore is the application interface to RcsProvider and provides access methods to
* RCS related database tables.
- *
- * @hide - TODO: make public
*/
public class RcsMessageStore {
/**
diff --git a/telephony/java/android/telephony/ims/RcsMessageStoreException.java b/telephony/java/android/telephony/ims/RcsMessageStoreException.java
index 7c00749b1690..f25bb173be37 100644
--- a/telephony/java/android/telephony/ims/RcsMessageStoreException.java
+++ b/telephony/java/android/telephony/ims/RcsMessageStoreException.java
@@ -19,8 +19,6 @@ package android.telephony.ims;
/**
* An exception that happened on {@link RcsMessageStore} or one of the derived storage classes in
* {@link android.telephony.ims}
- *
- * @hide - TODO: make public
*/
public class RcsMessageStoreException extends Exception {
diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessage.java b/telephony/java/android/telephony/ims/RcsOutgoingMessage.java
index dfcdee4a803d..06fb83268afb 100644
--- a/telephony/java/android/telephony/ims/RcsOutgoingMessage.java
+++ b/telephony/java/android/telephony/ims/RcsOutgoingMessage.java
@@ -23,8 +23,6 @@ import java.util.List;
/**
* This is a single instance of a message sent over RCS.
- *
- * @hide - TODO: make public
*/
public class RcsOutgoingMessage extends RcsMessage {
RcsOutgoingMessage(int id) {
diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java b/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java
index ca466e8c9d3e..979634a069df 100644
--- a/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java
+++ b/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java
@@ -23,8 +23,6 @@ import android.os.Parcelable;
* {@link RcsOutgoingMessageCreationParams} is a collection of parameters that should be passed
* into {@link RcsThread#addOutgoingMessage(RcsOutgoingMessageCreationParams)} to generate an
* {@link RcsOutgoingMessage} on that {@link RcsThread}
- *
- * @hide - TODO: make public
*/
public final class RcsOutgoingMessageCreationParams extends RcsMessageCreationParams
implements Parcelable {
diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessageDelivery.java b/telephony/java/android/telephony/ims/RcsOutgoingMessageDelivery.java
index 5a3062a69e3f..1c87b13f0dfb 100644
--- a/telephony/java/android/telephony/ims/RcsOutgoingMessageDelivery.java
+++ b/telephony/java/android/telephony/ims/RcsOutgoingMessageDelivery.java
@@ -21,8 +21,6 @@ import android.annotation.WorkerThread;
/**
* This class holds the delivery information of an {@link RcsOutgoingMessage} for each
* {@link RcsParticipant} that the message was intended for.
- *
- * @hide - TODO: make public
*/
public class RcsOutgoingMessageDelivery {
// The participant that this delivery is intended for
diff --git a/telephony/java/android/telephony/ims/RcsParticipant.java b/telephony/java/android/telephony/ims/RcsParticipant.java
index 37b827b8e83c..7ba5d8e65f76 100644
--- a/telephony/java/android/telephony/ims/RcsParticipant.java
+++ b/telephony/java/android/telephony/ims/RcsParticipant.java
@@ -20,8 +20,6 @@ import android.annotation.WorkerThread;
/**
* RcsParticipant is an RCS capable contact that can participate in {@link RcsThread}s.
- *
- * @hide - TODO: make public
*/
public class RcsParticipant {
// The row ID of this participant in the database
diff --git a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java
index aa278b38cf81..c9a2b0d07bc8 100644
--- a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java
+++ b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java
@@ -23,8 +23,6 @@ import android.os.Parcelable;
/**
* An event that indicates an {@link RcsParticipant}'s alias was changed. Please see US18-2 - GSMA
* RCC.71 (RCS Universal Profile Service Definition Document)
- *
- * @hide - TODO: make public
*/
public final class RcsParticipantAliasChangedEvent extends RcsEvent implements Parcelable {
// The ID of the participant that changed their alias
diff --git a/telephony/java/android/telephony/ims/RcsParticipantQueryParams.java b/telephony/java/android/telephony/ims/RcsParticipantQueryParams.java
index 57c67fa7aa03..d24d079d7038 100644
--- a/telephony/java/android/telephony/ims/RcsParticipantQueryParams.java
+++ b/telephony/java/android/telephony/ims/RcsParticipantQueryParams.java
@@ -30,8 +30,6 @@ import java.security.InvalidParameterException;
* The parameters to pass into
* {@link RcsMessageStore#getRcsParticipants(RcsParticipantQueryParams)} in order to select a
* subset of {@link RcsThread}s present in the message store.
- *
- * @hide - TODO: make public
*/
public final class RcsParticipantQueryParams implements Parcelable {
/**
diff --git a/telephony/java/android/telephony/ims/RcsParticipantQueryResult.java b/telephony/java/android/telephony/ims/RcsParticipantQueryResult.java
index 4eae39d1a2c6..505f1a55d1f0 100644
--- a/telephony/java/android/telephony/ims/RcsParticipantQueryResult.java
+++ b/telephony/java/android/telephony/ims/RcsParticipantQueryResult.java
@@ -28,8 +28,6 @@ import java.util.List;
* The result of a {@link RcsMessageStore#getRcsParticipants(RcsParticipantQueryParams)}
* call. This class allows getting the token for querying the next batch of participants in order to
* prevent handling large amounts of data at once.
- *
- * @hide - TODO: make public
*/
public final class RcsParticipantQueryResult implements Parcelable {
// A token for the caller to continue their query for the next batch of results
diff --git a/telephony/java/android/telephony/ims/RcsQueryContinuationToken.java b/telephony/java/android/telephony/ims/RcsQueryContinuationToken.java
index c1ff39652397..08643de51d40 100644
--- a/telephony/java/android/telephony/ims/RcsQueryContinuationToken.java
+++ b/telephony/java/android/telephony/ims/RcsQueryContinuationToken.java
@@ -31,8 +31,6 @@ import java.lang.annotation.RetentionPolicy;
* @see RcsMessageQueryResult#getContinuationToken()
* @see RcsParticipantQueryResult#getContinuationToken()
* @see RcsThreadQueryResult#getContinuationToken()
- *
- * @hide - TODO: make public
*/
public final class RcsQueryContinuationToken implements Parcelable {
/**
diff --git a/telephony/java/android/telephony/ims/RcsThread.java b/telephony/java/android/telephony/ims/RcsThread.java
index 88655865f47b..e015dd3e9c0a 100644
--- a/telephony/java/android/telephony/ims/RcsThread.java
+++ b/telephony/java/android/telephony/ims/RcsThread.java
@@ -27,8 +27,6 @@ import com.android.internal.annotations.VisibleForTesting;
/**
* RcsThread represents a single RCS conversation thread. It holds messages that were sent and
* received and events that occurred on that thread.
- *
- * @hide - TODO: make public
*/
public abstract class RcsThread {
/**
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryParams.java b/telephony/java/android/telephony/ims/RcsThreadQueryParams.java
index ba32e320c95b..05a5a3917691 100644
--- a/telephony/java/android/telephony/ims/RcsThreadQueryParams.java
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryParams.java
@@ -35,8 +35,6 @@ import java.util.Set;
/**
* The parameters to pass into {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParams)} in
* order to select a subset of {@link RcsThread}s present in the message store.
- *
- * @hide - TODO: make public
*/
public final class RcsThreadQueryParams implements Parcelable {
/**
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryResult.java b/telephony/java/android/telephony/ims/RcsThreadQueryResult.java
index a91126b89cce..1cac61d1aa64 100644
--- a/telephony/java/android/telephony/ims/RcsThreadQueryResult.java
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryResult.java
@@ -32,8 +32,6 @@ import java.util.List;
* The result of a {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParams)}
* call. This class allows getting the token for querying the next batch of threads in order to
* prevent handling large amounts of data at once.
- *
- * @hide - TODO: make public
*/
public final class RcsThreadQueryResult implements Parcelable {
// A token for the caller to continue their query for the next batch of results
diff --git a/telephony/java/com/android/internal/telephony/ISetOpportunisticDataCallback.aidl b/telephony/java/com/android/internal/telephony/ISetOpportunisticDataCallback.aidl
new file mode 100644
index 000000000000..7a78f3454aac
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ISetOpportunisticDataCallback.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+/**
+ * Callback to provide asynchronous result of setPreferredOpportunisticData.
+ * @hide
+ */
+oneway interface ISetOpportunisticDataCallback {
+ void onComplete(int result);
+}
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 6ce9de4ca677..75a4d8227e23 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -17,6 +17,7 @@
package com.android.internal.telephony;
import android.telephony.SubscriptionInfo;
+import com.android.internal.telephony.ISetOpportunisticDataCallback;
interface ISub {
/**
@@ -217,10 +218,14 @@ interface ISub {
* designed to overwrite default data subscription temporarily.
*
* @param subId which subscription is preferred to for cellular data.
+ * @param needValidation whether validation is needed before switching.
+ * @param callback callback upon request completion.
+ *
* @hide
*
*/
- void setPreferredDataSubscriptionId(int subId);
+ void setPreferredDataSubscriptionId(int subId, boolean needValidation,
+ ISetOpportunisticDataCallback callback);
/**
* Get which subscription is preferred for cellular data.
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index bc43feaf0e15..7089ee5671c2 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -765,7 +765,7 @@ interface ITelephony {
* @param subId the id of the subscription.
* @return CellNetworkScanResult containing status of scan and networks.
*/
- CellNetworkScanResult getCellNetworkScanResults(int subId);
+ CellNetworkScanResult getCellNetworkScanResults(int subId, String callingPackage);
/**
* Perform a radio network scan and return the id of this scan.
@@ -774,10 +774,11 @@ interface ITelephony {
* @param request Defines all the configs for network scan.
* @param messenger Callback messages will be sent using this messenger.
* @param binder the binder object instantiated in TelephonyManager.
+ * @param callingPackage the calling package
* @return An id for this scan.
*/
int requestNetworkScan(int subId, in NetworkScanRequest request, in Messenger messenger,
- in IBinder binder);
+ in IBinder binder, in String callingPackage);
/**
* Stop an existing radio network scan.
@@ -1837,7 +1838,7 @@ interface ITelephony {
* @hide
*/
boolean isMultisimCarrierRestricted();
-
+
/**
* Switch configs to enable multi-sim or switch back to single-sim
* @hide
@@ -1846,6 +1847,7 @@ interface ITelephony {
/**
* Get if reboot is required upon altering modems configurations
+ * @hide
*/
boolean isRebootRequiredForModemConfigChange();
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index b9ec7bf56370..9d78bf4bfb53 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -334,8 +334,7 @@ public final class TelephonyPermissions {
// settings to individually disable the new restrictions for privileged, preloaded
// non-privileged, and non-preinstalled apps.
if (!isIdentifierCheckDisabled() && (
- (isPrivApp && !relaxPrivDeviceIdentifierCheck)
- || (!isPreinstalled && !relax3PDeviceIdentifierCheck)
+ (!isPreinstalled && !relax3PDeviceIdentifierCheck)
|| (isPreinstalled && !isPrivApp && !relaxNonPrivDeviceIdentifierCheck))) {
// The current package should only be reported in StatsLog if it has not previously been
// reported for the currently invoked device identifier method.
diff --git a/telephony/java/com/android/internal/telephony/cdma/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/BearerData.java
index a4cd56b9e3e2..694cc69c2b3f 100644
--- a/telephony/java/com/android/internal/telephony/cdma/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/BearerData.java
@@ -596,6 +596,45 @@ public final class BearerData {
System.arraycopy(payload, 0, uData.payload, udhBytes, payload.length);
}
+ private static void encode7bitAsciiEms(UserData uData, byte[] udhData, boolean force)
+ throws CodingException
+ {
+ try {
+ Rlog.d(LOG_TAG, "encode7bitAsciiEms");
+ int udhBytes = udhData.length + 1; // Add length octet.
+ int udhSeptets = ((udhBytes * 8) + 6) / 7;
+ int paddingBits = (udhSeptets * 7) - (udhBytes * 8);
+ String msg = uData.payloadStr;
+ byte[] payload ;
+ int msgLen = msg.length();
+ BitwiseOutputStream outStream = new BitwiseOutputStream(msgLen +
+ (paddingBits > 0 ? 1 : 0));
+ outStream.write(paddingBits, 0);
+ for (int i = 0; i < msgLen; i++) {
+ int charCode = UserData.charToAscii.get(msg.charAt(i), -1);
+ if (charCode == -1) {
+ if (force) {
+ outStream.write(7, UserData.UNENCODABLE_7_BIT_CHAR);
+ } else {
+ throw new CodingException("cannot ASCII encode (" + msg.charAt(i) + ")");
+ }
+ } else {
+ outStream.write(7, charCode);
+ }
+ }
+ payload = outStream.toByteArray();
+ uData.msgEncoding = UserData.ENCODING_7BIT_ASCII;
+ uData.msgEncodingSet = true;
+ uData.numFields = udhSeptets + uData.payloadStr.length();
+ uData.payload = new byte[udhBytes + payload.length];
+ uData.payload[0] = (byte)udhData.length;
+ System.arraycopy(udhData, 0, uData.payload, 1, udhData.length);
+ System.arraycopy(payload, 0, uData.payload, udhBytes, payload.length);
+ } catch (BitwiseOutputStream.AccessException ex) {
+ throw new CodingException("7bit ASCII encode failed: " + ex);
+ }
+ }
+
private static void encodeEmsUserDataPayload(UserData uData)
throws CodingException
{
@@ -605,6 +644,8 @@ public final class BearerData {
encode7bitEms(uData, headerData, true);
} else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) {
encode16bitEms(uData, headerData);
+ } else if (uData.msgEncoding == UserData.ENCODING_7BIT_ASCII) {
+ encode7bitAsciiEms(uData, headerData, true);
} else {
throw new CodingException("unsupported EMS user data encoding (" +
uData.msgEncoding + ")");
@@ -1056,15 +1097,18 @@ public final class BearerData {
throws CodingException
{
try {
- offset *= 8;
+ int offsetBits = offset * 8;
+ int offsetSeptets = (offsetBits + 6) / 7;
+ numFields -= offsetSeptets;
+
StringBuffer strBuf = new StringBuffer(numFields);
BitwiseInputStream inStream = new BitwiseInputStream(data);
- int wantedBits = (offset * 8) + (numFields * 7);
+ int wantedBits = (offsetSeptets * 7) + (numFields * 7);
if (inStream.available() < wantedBits) {
throw new CodingException("insufficient data (wanted " + wantedBits +
" bits, but only have " + inStream.available() + ")");
}
- inStream.skip(offset);
+ inStream.skip(offsetSeptets * 7);
for (int i = 0; i < numFields; i++) {
int charCode = inStream.read(7);
if ((charCode >= UserData.ASCII_MAP_BASE_INDEX) &&
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 9080e23eb88f..1da5eac27002 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -864,8 +864,9 @@ public class SmsMessage extends SmsMessageBase {
Rlog.d(LOG_TAG, "MO raw BearerData = '" + HexDump.toHexString(encodedBearerData) + "'");
}
- int teleservice = bearerData.hasUserDataHeader ?
- SmsEnvelope.TELESERVICE_WEMT : SmsEnvelope.TELESERVICE_WMT;
+ int teleservice = (bearerData.hasUserDataHeader
+ && userData.msgEncoding != UserData.ENCODING_7BIT_ASCII)
+ ? SmsEnvelope.TELESERVICE_WEMT : SmsEnvelope.TELESERVICE_WMT;
SmsEnvelope envelope = new SmsEnvelope();
envelope.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
diff --git a/test-runner/Android.mk b/test-runner/Android.mk
deleted file mode 100644
index 18bde8517351..000000000000
--- a/test-runner/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#
-# Copyright (C) 2008 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# 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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-# additionally, build unit tests in a separate .apk
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/test-runner/tests/Android.bp b/test-runner/tests/Android.bp
new file mode 100644
index 000000000000..03c73986118d
--- /dev/null
+++ b/test-runner/tests/Android.bp
@@ -0,0 +1,40 @@
+// Copyright 2010, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "FrameworkTestRunnerTests",
+
+ // We only want this apk build for tests.
+ //
+ // Run the tests using the following commands:
+ // adb install -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworkTestRunnerTests/FrameworkTestRunnerTests.apk
+ // adb shell am instrument \
+ // -e notAnnotation android.test.suitebuilder.examples.error.RunAsPartOfSeparateTest \
+ // -w com.android.frameworks.testrunner.tests/android.test.InstrumentationTestRunner \
+ //
+
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ ],
+ static_libs: ["junit"],
+
+ // Include all test java files.
+ srcs: ["src/**/*.java"],
+
+ // Because of android.test.mock.
+ platform_apis: true,
+
+}
diff --git a/test-runner/tests/Android.mk b/test-runner/tests/Android.mk
deleted file mode 100644
index f97d1c986b1c..000000000000
--- a/test-runner/tests/Android.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright 2010, The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-#
-# Run the tests using the following commands:
-# adb install -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworkTestRunnerTests/FrameworkTestRunnerTests.apk
-# adb shell am instrument \
- -e notAnnotation android.test.suitebuilder.examples.error.RunAsPartOfSeparateTest \
- -w com.android.frameworks.testrunner.tests/android.test.InstrumentationTestRunner
-#
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := FrameworkTestRunnerTests
-# Because of android.test.mock.
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
-
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
index d5549cc1355e..07b3a97817a3 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
@@ -439,6 +439,14 @@ public class ActivityTestMain extends Activity {
return true;
}
});
+ menu.add("Require unknown permission").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+ @Override public boolean onMenuItemClick(MenuItem item) {
+ final Intent intent = new Intent(SLOW_RECEIVER_ACTION);
+ intent.putExtra(SLOW_RECEIVER_EXTRA, 5038);
+ sendOrderedBroadcast(intent, "com.google.android.test.activity.permission.UNDEFINED");
+ return true;
+ }
+ });
menu.add("Stack Doc").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override public boolean onMenuItemClick(MenuItem item) {
ActivityManager.AppTask task = findDocTask();
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 1a4ec94d77b4..7b8c154dea1e 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -1028,8 +1028,28 @@
</activity>
<activity
- android:name="PositionListenerActivity"
- android:label="RenderNode/PositionListener"
+ android:name="PositionListenerActivity"
+ android:label="RenderNode/PositionListener"
+ android:screenOrientation="fullSensor">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.hwui.TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity
+ android:name="CustomRenderer"
+ android:label="HardwareRenderer/HelloTakeSurface"
+ android:screenOrientation="fullSensor">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.hwui.TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity
+ android:name="MyLittleTextureView"
+ android:label="HardwareRenderer/MyLittleTextureView"
android:screenOrientation="fullSensor">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java b/tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java
new file mode 100644
index 000000000000..60bd60f0bfd1
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.graphics.HardwareRenderer;
+import android.graphics.Paint;
+import android.graphics.RecordingCanvas;
+import android.graphics.RenderNode;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.SurfaceHolder;
+
+public class CustomRenderer extends Activity {
+ private RenderNode mContent = new RenderNode("CustomRenderer");
+ private HardwareRenderer mRenderer = new HardwareRenderer();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().takeSurface(mSurfaceCallbacks);
+ }
+
+ private SurfaceHolder.Callback2 mSurfaceCallbacks = new SurfaceHolder.Callback2() {
+
+ @Override
+ public void surfaceRedrawNeeded(SurfaceHolder holder) {
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ mContent.setLeftTopRightBottom(0, 0, width, height);
+ RecordingCanvas canvas = mContent.startRecording();
+ canvas.drawColor(Color.WHITE);
+ Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ paint.setColor(Color.BLACK);
+ paint.setTextAlign(Paint.Align.CENTER);
+ paint.setTextSize(Math.min(width, height) * .05f);
+ canvas.drawText("Hello custom renderer!", width / 2, height / 2, paint);
+ mContent.endRecording();
+
+ mRenderer.setContentRoot(mContent);
+ mRenderer.setSurface(holder.getSurface());
+ mRenderer.createRenderRequest()
+ .setVsyncTime(System.nanoTime())
+ .setFrameCommitCallback(Runnable::run, () -> {
+ Log.d("CustomRenderer", "Frame committed!");
+ })
+ .syncAndDraw();
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ mRenderer.destroy();
+ }
+ };
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MyLittleTextureView.java b/tests/HwAccelerationTest/src/com/android/test/hwui/MyLittleTextureView.java
new file mode 100644
index 000000000000..8bd7d797aea3
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/MyLittleTextureView.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorSpace;
+import android.graphics.HardwareRenderer;
+import android.graphics.Outline;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.RenderNode;
+import android.hardware.HardwareBuffer;
+import android.media.Image;
+import android.media.ImageReader;
+import android.os.Bundle;
+import android.widget.ImageView;
+
+public class MyLittleTextureView extends Activity {
+ private RenderNode mContent = new RenderNode("CustomRenderer");
+ private HardwareRenderer mRenderer = new HardwareRenderer();
+ private ImageView mImageView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mImageView = new ImageView(this);
+ mImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
+ setContentView(mImageView);
+
+ ImageReader reader = ImageReader.newInstance(100, 100, PixelFormat.RGBA_8888, 3,
+ HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE | HardwareBuffer.USAGE_GPU_COLOR_OUTPUT);
+ mRenderer.setSurface(reader.getSurface());
+ mRenderer.setLightSourceAlpha(0.0f, 1.0f);
+ mRenderer.setLightSourceGeometry(100 / 2f, 0f, 800.0f, 20.0f);
+ mContent.setLeftTopRightBottom(0, 0, 100, 100);
+
+ Rect childRect = new Rect(25, 25, 65, 65);
+ RenderNode childNode = new RenderNode("shadowCaster");
+ childNode.setLeftTopRightBottom(childRect.left, childRect.top,
+ childRect.right, childRect.bottom);
+ Outline outline = new Outline();
+ outline.setRect(new Rect(0, 0, childRect.width(), childRect.height()));
+ outline.setAlpha(1f);
+ childNode.setOutline(outline);
+ {
+ Canvas canvas = childNode.startRecording();
+ canvas.drawColor(Color.BLUE);
+ }
+ childNode.endRecording();
+ childNode.setElevation(20f);
+
+ {
+ Canvas canvas = mContent.startRecording();
+ canvas.drawColor(Color.WHITE);
+ canvas.enableZ();
+ canvas.drawRenderNode(childNode);
+ canvas.disableZ();
+ }
+ mContent.endRecording();
+ mRenderer.setContentRoot(mContent);
+ mRenderer.createRenderRequest()
+ .setWaitForPresent(true)
+ .syncAndDraw();
+ Image image = reader.acquireNextImage();
+ Bitmap bitmap = Bitmap.wrapHardwareBuffer(image.getHardwareBuffer(),
+ ColorSpace.get(ColorSpace.Named.SRGB));
+ mImageView.setImageBitmap(bitmap);
+ image.close();
+ }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index e2d59d648563..e57d838bcf92 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -554,7 +554,7 @@ public class ConnectivityServiceTest {
if (mNmValidationRedirectUrl != null) {
mNmCallbacks.showProvisioningNotification(
- "test_provisioning_notif_action");
+ "test_provisioning_notif_action", "com.android.test.package");
mNmProvNotificationRequested = true;
}
} catch (RemoteException e) {
@@ -3817,11 +3817,14 @@ public class ConnectivityServiceTest {
}
@Test
- public void testNattSocketKeepalives() throws Exception {
+ public void testNattSocketKeepalives_SingleThreadExecutor() throws Exception {
final ExecutorService executorSingleThread = Executors.newSingleThreadExecutor();
doTestNattSocketKeepalivesWithExecutor(executorSingleThread);
executorSingleThread.shutdown();
+ }
+ @Test
+ public void testNattSocketKeepalives_InlineExecutor() throws Exception {
final Executor executorInline = (Runnable r) -> r.run();
doTestNattSocketKeepalivesWithExecutor(executorInline);
}
@@ -3963,6 +3966,7 @@ public class ConnectivityServiceTest {
testSocket2.close();
mWiFiNetworkAgent.disconnect();
+ waitFor(mWiFiNetworkAgent.getDisconnectedCV());
}
@Test
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index b6356076db60..a4a735d1a89d 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -35,6 +35,7 @@ import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -274,6 +275,11 @@ public class TetheringTest {
isTetheringSupportedCalls++;
return true;
}
+
+ @Override
+ public int getDefaultDataSubscriptionId() {
+ return INVALID_SUBSCRIPTION_ID;
+ }
}
private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6,
diff --git a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
index ec286759354a..193f3806dbf6 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
@@ -21,6 +21,7 @@ import static android.net.ConnectivityManager.TETHERING_WIFI;
import static android.net.ConnectivityManager.TETHER_ERROR_ENTITLEMENT_UNKONWN;
import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -140,7 +141,8 @@ public final class EntitlementManagerTest {
mMockContext = new MockContext(mContext);
mSM = new TestStateMachine();
mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, mSystemProperties);
- mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
+ mEnMgr.updateConfiguration(
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
}
@After
@@ -168,7 +170,8 @@ public final class EntitlementManagerTest {
@Test
public void canRequireProvisioning() {
setupForRequiredProvisioning();
- mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
+ mEnMgr.updateConfiguration(
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
assertTrue(mEnMgr.isTetherProvisioningRequired());
}
@@ -177,7 +180,8 @@ public final class EntitlementManagerTest {
setupForRequiredProvisioning();
when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
.thenReturn(null);
- mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
+ mEnMgr.updateConfiguration(
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
// Couldn't get the CarrierConfigManager, but still had a declared provisioning app.
// Therefore provisioning still be required.
assertTrue(mEnMgr.isTetherProvisioningRequired());
@@ -187,7 +191,8 @@ public final class EntitlementManagerTest {
public void toleratesCarrierConfigMissing() {
setupForRequiredProvisioning();
when(mCarrierConfigManager.getConfig()).thenReturn(null);
- mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
+ mEnMgr.updateConfiguration(
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
// We still have a provisioning app configured, so still require provisioning.
assertTrue(mEnMgr.isTetherProvisioningRequired());
}
@@ -197,11 +202,13 @@ public final class EntitlementManagerTest {
setupForRequiredProvisioning();
when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
.thenReturn(null);
- mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
+ mEnMgr.updateConfiguration(
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
assertFalse(mEnMgr.isTetherProvisioningRequired());
when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
.thenReturn(new String[] {"malformedApp"});
- mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
+ mEnMgr.updateConfiguration(
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
assertFalse(mEnMgr.isTetherProvisioningRequired());
}
@@ -223,7 +230,8 @@ public final class EntitlementManagerTest {
assertFalse(mEnMgr.everRunUiEntitlement);
setupForRequiredProvisioning();
- mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
+ mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
+ INVALID_SUBSCRIPTION_ID));
// 2. No cache value and don't need to run entitlement check.
mEnMgr.everRunUiEntitlement = false;
receiver = new ResultReceiver(null) {
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
index 521778484d91..01b904d8f088 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
@@ -22,10 +22,12 @@ import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_NOT_REQUIRED;
import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_REQUIRED;
import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_UNSPECIFIED;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -44,26 +46,39 @@ import android.test.mock.MockContentResolver;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider;
-import java.util.Iterator;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Iterator;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class TetheringConfigurationTest {
private final SharedLog mLog = new SharedLog("TetheringConfigurationTest");
+
+ private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
@Mock private Context mContext;
@Mock private TelephonyManager mTelephonyManager;
@Mock private Resources mResources;
+ @Mock private Resources mResourcesForSubId;
private MockContentResolver mContentResolver;
private Context mMockContext;
private boolean mHasTelephonyManager;
+ private class MockTetheringConfiguration extends TetheringConfiguration {
+ MockTetheringConfiguration(Context ctx, SharedLog log, int id) {
+ super(ctx, log, id);
+ }
+
+ @Override
+ protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) {
+ return mResourcesForSubId;
+ }
+ }
+
private class MockContext extends BroadcastInterceptingContext {
MockContext(Context base) {
super(base);
@@ -99,6 +114,9 @@ public class TetheringConfigurationTest {
.thenReturn(new String[0]);
when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
.thenReturn(new int[0]);
+ when(mResources.getStringArray(
+ com.android.internal.R.array.config_mobile_hotspot_provision_app))
+ .thenReturn(new String[0]);
mContentResolver = new MockContentResolver();
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
mMockContext = new MockContext(mContext);
@@ -111,7 +129,8 @@ public class TetheringConfigurationTest {
mHasTelephonyManager = true;
when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_REQUIRED);
- final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+ final TetheringConfiguration cfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
assertTrue(cfg.isDunRequired);
assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN));
assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE));
@@ -127,7 +146,8 @@ public class TetheringConfigurationTest {
mHasTelephonyManager = true;
when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_NOT_REQUIRED);
- final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+ final TetheringConfiguration cfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
assertFalse(cfg.isDunRequired);
assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN));
assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE));
@@ -143,7 +163,8 @@ public class TetheringConfigurationTest {
mHasTelephonyManager = false;
when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED);
- final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+ final TetheringConfiguration cfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
assertTrue(cfg.isDunRequired);
assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN));
// Just to prove we haven't clobbered Wi-Fi:
@@ -160,7 +181,8 @@ public class TetheringConfigurationTest {
mHasTelephonyManager = false;
when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED);
- final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+ final TetheringConfiguration cfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator();
assertTrue(upstreamIterator.hasNext());
assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue());
@@ -181,7 +203,8 @@ public class TetheringConfigurationTest {
mHasTelephonyManager = false;
when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED);
- final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+ final TetheringConfiguration cfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator();
assertTrue(upstreamIterator.hasNext());
assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue());
@@ -199,7 +222,8 @@ public class TetheringConfigurationTest {
mHasTelephonyManager = false;
when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED);
- final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+ final TetheringConfiguration cfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator();
assertTrue(upstreamIterator.hasNext());
assertEquals(TYPE_WIFI, upstreamIterator.next().intValue());
@@ -214,7 +238,8 @@ public class TetheringConfigurationTest {
public void testNewDhcpServerDisabled() {
Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 1);
- final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+ final TetheringConfiguration cfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
assertTrue(cfg.enableLegacyDhcpServer);
}
@@ -222,7 +247,41 @@ public class TetheringConfigurationTest {
public void testNewDhcpServerEnabled() {
Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0);
- final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+ final TetheringConfiguration cfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
assertFalse(cfg.enableLegacyDhcpServer);
}
+
+ @Test
+ public void testGetResourcesBySubId() {
+ setUpResourceForSubId();
+ final TetheringConfiguration cfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+ assertTrue(cfg.provisioningApp.length == 0);
+ final int anyValidSubId = 1;
+ final MockTetheringConfiguration mockCfg =
+ new MockTetheringConfiguration(mMockContext, mLog, anyValidSubId);
+ assertEquals(mockCfg.provisioningApp[0], PROVISIONING_APP_NAME[0]);
+ assertEquals(mockCfg.provisioningApp[1], PROVISIONING_APP_NAME[1]);
+ }
+
+ private void setUpResourceForSubId() {
+ when(mResourcesForSubId.getStringArray(
+ com.android.internal.R.array.config_tether_dhcp_range)).thenReturn(new String[0]);
+ when(mResourcesForSubId.getStringArray(
+ com.android.internal.R.array.config_tether_usb_regexs)).thenReturn(new String[0]);
+ when(mResourcesForSubId.getStringArray(
+ com.android.internal.R.array.config_tether_wifi_regexs))
+ .thenReturn(new String[]{ "test_wlan\\d" });
+ when(mResourcesForSubId.getStringArray(
+ com.android.internal.R.array.config_tether_bluetooth_regexs))
+ .thenReturn(new String[0]);
+ when(mResourcesForSubId.getIntArray(
+ com.android.internal.R.array.config_tether_upstream_types))
+ .thenReturn(new int[0]);
+ when(mResourcesForSubId.getStringArray(
+ com.android.internal.R.array.config_mobile_hotspot_provision_app))
+ .thenReturn(PROVISIONING_APP_NAME);
+ }
+
}
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index 73b568e77689..9a1d94288363 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -151,10 +151,12 @@ message Overlayable {
// Represents an overlayable <item> declaration within an <overlayable> tag.
message OverlayableItem {
enum Policy {
- PUBLIC = 0;
- SYSTEM = 1;
- VENDOR = 2;
- PRODUCT = 3;
+ NONE = 0;
+ PUBLIC = 1;
+ SYSTEM = 2;
+ VENDOR = 3;
+ PRODUCT = 4;
+ SIGNATURE = 5;
}
// The location of the <item> declaration in source.
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 85bf6f218ba0..582a5b869c65 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -294,22 +294,6 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
}
}
- if (el->FindAttribute("", "platformBuildVersionCode") == nullptr) {
- auto versionCode = el->FindAttribute(xml::kSchemaAndroid, "versionCode");
- if (versionCode != nullptr) {
- el->attributes.push_back(xml::Attribute{"", "platformBuildVersionCode",
- versionCode->value});
- }
- }
-
- if (el->FindAttribute("", "platformBuildVersionName") == nullptr) {
- auto versionName = el->FindAttribute(xml::kSchemaAndroid, "versionName");
- if (versionName != nullptr) {
- el->attributes.push_back(xml::Attribute{"", "platformBuildVersionName",
- versionName->value});
- }
- }
-
return true;
});
@@ -489,8 +473,14 @@ bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) {
// Make sure we un-compile the value if it was set to something else.
attr->compiled_value = {};
+ attr->value = options_.compile_sdk_version.value();
+
+ attr = root->FindOrCreateAttribute("", "platformBuildVersionCode");
+ // Make sure we un-compile the value if it was set to something else.
+ attr->compiled_value = {};
attr->value = options_.compile_sdk_version.value();
+
}
if (options_.compile_sdk_version_codename) {
@@ -499,7 +489,12 @@ bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) {
// Make sure we un-compile the value if it was set to something else.
attr->compiled_value = {};
+ attr->value = options_.compile_sdk_version_codename.value();
+ attr = root->FindOrCreateAttribute("", "platformBuildVersionName");
+
+ // Make sure we un-compile the value if it was set to something else.
+ attr->compiled_value = {};
attr->value = options_.compile_sdk_version_codename.value();
}
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index adea6273bc8b..4842f62e53b5 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -725,6 +725,43 @@ TEST_F(ManifestFixerTest, InsertCompileSdkVersions) {
attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename");
ASSERT_THAT(attr, NotNull());
EXPECT_THAT(attr->value, StrEq("P"));
+
+ attr = manifest->root->FindAttribute("", "platformBuildVersionCode");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("28"));
+
+ attr = manifest->root->FindAttribute("", "platformBuildVersionName");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("P"));
+}
+
+TEST_F(ManifestFixerTest, OverrideCompileSdkVersions) {
+ std::string input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"
+ compileSdkVersion="27" compileSdkVersionCodename="O"
+ platformBuildVersionCode="27" platformBuildVersionName="O"/>)";
+ ManifestFixerOptions options;
+ options.compile_sdk_version = {"28"};
+ options.compile_sdk_version_codename = {"P"};
+
+ std::unique_ptr<xml::XmlResource> manifest = VerifyWithOptions(input, options);
+ ASSERT_THAT(manifest, NotNull());
+
+ xml::Attribute* attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersion");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("28"));
+
+ attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("P"));
+
+ attr = manifest->root->FindAttribute("", "platformBuildVersionCode");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("28"));
+
+ attr = manifest->root->FindAttribute("", "platformBuildVersionName");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("P"));
}
TEST_F(ManifestFixerTest, UnexpectedElementsInManifest) {
@@ -750,59 +787,6 @@ TEST_F(ManifestFixerTest, UnexpectedElementsInManifest) {
ASSERT_THAT(manifest, IsNull());
}
-TEST_F(ManifestFixerTest, InsertPlatformBuildVersions) {
- // Test for insertion when versionCode and versionName are included in the manifest
- {
- std::string input = R"(
- <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"
- android:versionCode="27" android:versionName="O"/>)";
- std::unique_ptr<xml::XmlResource> manifest = Verify(input);
- ASSERT_THAT(manifest, NotNull());
-
- xml::Attribute* attr = manifest->root->FindAttribute("", "platformBuildVersionCode");
- ASSERT_THAT(attr, NotNull());
- EXPECT_THAT(attr->value, StrEq("27"));
- attr = manifest->root->FindAttribute("", "platformBuildVersionName");
- ASSERT_THAT(attr, NotNull());
- EXPECT_THAT(attr->value, StrEq("O"));
- }
-
- // Test for insertion when versionCode and versionName defaults are specified
- {
- std::string input = R"(
- <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"/>)";
- ManifestFixerOptions options;
- options.version_code_default = {"27"};
- options.version_name_default = {"O"};
- std::unique_ptr<xml::XmlResource> manifest = VerifyWithOptions(input, options);
- ASSERT_THAT(manifest, NotNull());
-
- xml::Attribute* attr = manifest->root->FindAttribute("", "platformBuildVersionCode");
- ASSERT_THAT(attr, NotNull());
- EXPECT_THAT(attr->value, StrEq("27"));
- attr = manifest->root->FindAttribute("", "platformBuildVersionName");
- ASSERT_THAT(attr, NotNull());
- EXPECT_THAT(attr->value, StrEq("O"));
- }
-
- // Test that the platform build version attributes are not changed if they are currently present
- {
- std::string input = R"(
- <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"
- android:versionCode="28" android:versionName="P"
- platformBuildVersionCode="27" platformBuildVersionName="O"/>)";
- std::unique_ptr<xml::XmlResource> manifest = Verify(input);
- ASSERT_THAT(manifest, NotNull());
-
- xml::Attribute* attr = manifest->root->FindAttribute("", "platformBuildVersionCode");
- ASSERT_THAT(attr, NotNull());
- EXPECT_THAT(attr->value, StrEq("27"));
- attr = manifest->root->FindAttribute("", "platformBuildVersionName");
- ASSERT_THAT(attr, NotNull());
- EXPECT_THAT(attr->value, StrEq("O"));
- }
-}
-
TEST_F(ManifestFixerTest, UsesLibraryMustHaveNonEmptyName) {
std::string input = R"(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
diff --git a/tools/preload/Android.bp b/tools/preload/Android.bp
new file mode 100644
index 000000000000..809ee474969a
--- /dev/null
+++ b/tools/preload/Android.bp
@@ -0,0 +1,17 @@
+java_library_host {
+ name: "preload",
+ srcs: [
+ "Compile.java",
+ "LoadedClass.java",
+ "MemoryUsage.java",
+ "Operation.java",
+ "Policy.java",
+ "PrintCsv.java",
+ "PrintHtmlDiff.java",
+ "PrintPsTree.java",
+ "Proc.java",
+ "Record.java",
+ "Root.java",
+ "WritePreloadedClassFile.java",
+ ],
+}
diff --git a/tools/preload/Android.mk b/tools/preload/Android.mk
deleted file mode 100644
index 14a4547cccbf..000000000000
--- a/tools/preload/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- Compile.java \
- LoadedClass.java \
- MemoryUsage.java \
- Operation.java \
- Policy.java \
- PrintCsv.java \
- PrintHtmlDiff.java \
- PrintPsTree.java \
- Proc.java \
- Record.java \
- Root.java \
- WritePreloadedClassFile.java
-
-LOCAL_MODULE:= preload
-
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/preload/loadclass/Android.bp b/tools/preload/loadclass/Android.bp
new file mode 100644
index 000000000000..6f12015dae2b
--- /dev/null
+++ b/tools/preload/loadclass/Android.bp
@@ -0,0 +1,4 @@
+java_test {
+ name: "loadclass",
+ srcs: ["**/*.java"],
+}
diff --git a/tools/preload/loadclass/Android.mk b/tools/preload/loadclass/Android.mk
deleted file mode 100644
index 65828be617df..000000000000
--- a/tools/preload/loadclass/Android.mk
+++ /dev/null
@@ -1,9 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MODULE := loadclass
-
-include $(BUILD_JAVA_LIBRARY)
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 55440d2261d3..0270c72ff240 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -688,7 +688,7 @@ write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributio
build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
size_t i = 0;
- // Print constants
+ // Print atom constants
for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
atom != atoms.decls.end(); atom++) {
string constant = make_constant_name(atom->name);
@@ -714,6 +714,30 @@ write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributio
fprintf(out, "};\n");
fprintf(out, "\n");
+ // Print constants for the enum values.
+ fprintf(out, "//\n");
+ fprintf(out, "// Constants for enum values\n");
+ fprintf(out, "//\n\n");
+ for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+ atom != atoms.decls.end(); atom++) {
+ for (vector<AtomField>::const_iterator field = atom->fields.begin();
+ field != atom->fields.end(); field++) {
+ if (field->javaType == JAVA_TYPE_ENUM) {
+ fprintf(out, "// Values for %s.%s\n", atom->message.c_str(),
+ field->name.c_str());
+ for (map<int, string>::const_iterator value = field->enumValues.begin();
+ value != field->enumValues.end(); value++) {
+ fprintf(out, "const int32_t %s__%s__%s = %d;\n",
+ make_constant_name(atom->message).c_str(),
+ make_constant_name(field->name).c_str(),
+ make_constant_name(value->second).c_str(),
+ value->first);
+ }
+ fprintf(out, "\n");
+ }
+ }
+ }
+
fprintf(out, "struct BytesField {\n");
fprintf(out,
" BytesField(char const* array, size_t len) : arg(array), "
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 488de8789178..af9fdfbd364d 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -276,14 +276,19 @@ public class WifiInfo implements Parcelable {
/**
* Returns the service set identifier (SSID) of the current 802.11 network.
+ * <p>
* If the SSID can be decoded as UTF-8, it will be returned surrounded by double
- * quotation marks. Otherwise, it is returned as a string of hex digits. The
- * SSID may be &lt;unknown ssid&gt; if there is no network currently connected,
- * or if the caller has insufficient permissions to access the SSID.
- *
+ * quotation marks. Otherwise, it is returned as a string of hex digits.
+ * The SSID may be
+ * <lt>&lt;unknown ssid&gt;, if there is no network currently connected or if the caller has
+ * insufficient permissions to access the SSID.<lt>
+ * </p>
+ * <p>
* Prior to {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method
* always returned the SSID with no quotes around it.
- * @return the SSID
+ * </p>
+ *
+ * @return the SSID.
*/
public String getSSID() {
if (mWifiSsid != null) {
@@ -312,7 +317,13 @@ public class WifiInfo implements Parcelable {
/**
* Return the basic service set identifier (BSSID) of the current access point.
- * The BSSID may be {@code null} if there is no network currently connected.
+ * <p>
+ * The BSSID may be
+ * <lt>{@code null}, if there is no network currently connected.</lt>
+ * <lt>{@code "02:00:00:00:00:00"}, if the caller has insufficient permissions to access the
+ * BSSID.<lt>
+ * </p>
+ *
* @return the BSSID, in the form of a six-byte MAC address: {@code XX:XX:XX:XX:XX:XX}
*/
public String getBSSID() {
@@ -511,9 +522,13 @@ public class WifiInfo implements Parcelable {
/**
* Each configured network has a unique small integer ID, used to identify
- * the network when performing operations on the supplicant. This method
- * returns the ID for the currently connected network.
- * @return the network ID, or -1 if there is no currently connected network
+ * the network. This method returns the ID for the currently connected network.
+ * <p>
+ * The networkId may be {@code -1} if there is no currently connected network or if the caller
+ * has insufficient permissions to access the network ID.
+ * </p>
+ *
+ * @return the network ID.
*/
public int getNetworkId() {
return mNetworkId;
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 2cc1d8313225..5e5a59566ce5 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1149,9 +1149,6 @@ public class WifiManager {
* Return a list of all the networks configured for the current foreground
* user.
*
- * Requires the same permissions as {@link #getScanResults}.
- * If such access is not allowed, this API will always return an empty list.
- *
* Not all fields of WifiConfiguration are returned. Only the following
* fields are filled in:
* <ul>
@@ -1176,8 +1173,12 @@ public class WifiManager {
* when auto-connecting to wifi.
* <b>Compatibility Note:</b> For applications targeting
* {@link android.os.Build.VERSION_CODES#Q} or above, this API will return an empty list,
- * except to callers with Carrier privilege which will receive a restricted list only
- * containing configurations which they created.
+ * except for:
+ * <ul>
+ * <li>Device Owner (DO) & Profile Owner (PO) apps will have access to the full list.
+ * <li>Callers with Carrier privilege will receive a restricted list only containing
+ * configurations which they created.
+ * </ul>
*/
@Deprecated
@RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
@@ -4721,7 +4722,6 @@ public class WifiManager {
*
* @hide
*/
- @SystemApi
private static class EasyConnectCallbackProxy extends IDppCallback.Stub {
private final Executor mExecutor;
private final EasyConnectStatusCallback mEasyConnectStatusCallback;
diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
index a69c7a501452..333b82ccd146 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
@@ -421,7 +421,7 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc
* .setSsidPattern(new PatternMatcher("test", PatterMatcher.PATTERN_PREFIX))
* .setBssidPattern(MacAddress.fromString("10:03:23:00:00:00"),
* MacAddress.fromString("ff:ff:ff:00:00:00"))
- * .buildNetworkSpecifier()
+ * .build()
* final NetworkRequest request =
* new NetworkRequest.Builder()
* .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 460c633e16bd..233fa2cb4fff 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -413,17 +413,17 @@ public final class WifiNetworkSuggestion implements Parcelable {
* final WifiNetworkSuggestion suggestion1 =
* new Builder()
* .setSsid("test111111")
- * .buildNetworkSuggestion()
+ * .build()
* final WifiNetworkSuggestion suggestion2 =
* new Builder()
* .setSsid("test222222")
* .setWpa2Passphrase("test123456")
- * .buildNetworkSuggestion()
+ * .build()
* final WifiNetworkSuggestion suggestion3 =
* new Builder()
* .setSsid("test333333")
* .setWpa3Passphrase("test6789")
- * .buildNetworkSuggestion()
+ * .build()
* final List<WifiNetworkSuggestion> suggestionsList =
* new ArrayList<WifiNetworkSuggestion> {{
* add(suggestion1);
diff --git a/wifi/java/android/net/wifi/aware/ParcelablePeerHandle.java b/wifi/java/android/net/wifi/aware/ParcelablePeerHandle.java
new file mode 100644
index 000000000000..4ddf872f6cd2
--- /dev/null
+++ b/wifi/java/android/net/wifi/aware/ParcelablePeerHandle.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.aware;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A Parcelable {@link PeerHandle}. Can be constructed from a {@code PeerHandle} and then passed
+ * to any of the APIs which take a {@code PeerHandle} as inputs.
+ */
+public final class ParcelablePeerHandle extends PeerHandle implements Parcelable {
+ /**
+ * Construct a parcelable version of {@link PeerHandle}.
+ *
+ * @param peerHandle The {@link PeerHandle} to be made parcelable.
+ */
+ public ParcelablePeerHandle(PeerHandle peerHandle) {
+ super(peerHandle.peerId);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(peerId);
+ }
+
+ public static final Creator<ParcelablePeerHandle> CREATOR =
+ new Creator<ParcelablePeerHandle>() {
+ @Override
+ public ParcelablePeerHandle[] newArray(int size) {
+ return new ParcelablePeerHandle[size];
+ }
+
+ @Override
+ public ParcelablePeerHandle createFromParcel(Parcel in) {
+ int peerHandle = in.readInt();
+ return new ParcelablePeerHandle(new PeerHandle(peerHandle));
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/aware/PeerHandle.java b/wifi/java/android/net/wifi/aware/PeerHandle.java
index 1603d00fd88a..422e177ed7ad 100644
--- a/wifi/java/android/net/wifi/aware/PeerHandle.java
+++ b/wifi/java/android/net/wifi/aware/PeerHandle.java
@@ -16,9 +16,6 @@
package android.net.wifi.aware;
-import android.os.Parcel;
-import android.os.Parcelable;
-
/**
* Opaque object used to represent a Wi-Fi Aware peer. Obtained from discovery sessions in
* {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)} or
@@ -35,8 +32,9 @@ import android.os.Parcelable;
* configuration's service-specific information field,
* {@link PublishConfig.Builder#setServiceSpecificInfo(byte[])}, or match filter,
* {@link PublishConfig.Builder#setMatchFilter(java.util.List)}.
+ * <p>A parcelable handle object is available with {@link ParcelablePeerHandle}.
*/
-public final class PeerHandle implements Parcelable {
+public class PeerHandle {
/** @hide */
public PeerHandle(int peerId) {
this.peerId = peerId;
@@ -62,29 +60,4 @@ public final class PeerHandle implements Parcelable {
public int hashCode() {
return peerId;
}
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(peerId);
- }
-
- public static final Creator<PeerHandle> CREATOR = new Creator<PeerHandle>() {
- @Override
- public PeerHandle[] newArray(int size) {
- return new PeerHandle[size];
- }
-
- @Override
- public PeerHandle createFromParcel(Parcel in) {
- int peerHandle = in.readInt();
-
- return new PeerHandle(peerHandle);
- }
- };
-
}
diff --git a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
index 29f10e932e48..b3b5b2903471 100644
--- a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
+++ b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
@@ -61,6 +61,7 @@ public class TlvBufferUtils {
public static class TlvConstructor {
private int mTypeSize;
private int mLengthSize;
+ private ByteOrder mByteOrder = ByteOrder.BIG_ENDIAN;
private byte[] mArray;
private int mArrayLength;
@@ -84,6 +85,20 @@ public class TlvBufferUtils {
}
mTypeSize = typeSize;
mLengthSize = lengthSize;
+ mPosition = 0;
+ }
+
+ /**
+ * Configure the TLV constructor to use a particular byte order. Should be
+ * {@link ByteOrder#BIG_ENDIAN} (the default at construction) or
+ * {@link ByteOrder#LITTLE_ENDIAN}.
+ *
+ * @return The constructor to facilitate chaining
+ * {@code ctr.putXXX(..).putXXX(..)}.
+ */
+ public TlvConstructor setByteOrder(ByteOrder byteOrder) {
+ mByteOrder = byteOrder;
+ return this;
}
/**
@@ -96,6 +111,7 @@ public class TlvBufferUtils {
public TlvConstructor wrap(@Nullable byte[] array) {
mArray = array;
mArrayLength = (array == null) ? 0 : array.length;
+ mPosition = 0;
return this;
}
@@ -109,6 +125,7 @@ public class TlvBufferUtils {
public TlvConstructor allocate(int capacity) {
mArray = new byte[capacity];
mArrayLength = capacity;
+ mPosition = 0;
return this;
}
@@ -155,6 +172,18 @@ public class TlvBufferUtils {
}
/**
+ * Copies a raw byte into the TLV buffer - without a type or a length.
+ *
+ * @param b The byte to be inserted into the structure.
+ * @return The constructor to facilitate chaining {@code cts.putXXX(..).putXXX(..)}.
+ */
+ public TlvConstructor putRawByte(byte b) {
+ checkRawLength(1);
+ mArray[mPosition++] = b;
+ return this;
+ }
+
+ /**
* Copies a byte array into the TLV with the indicated type. For an LV
* formatted structure (i.e. typeLength=0 in {@link TlvConstructor
* TlvConstructor(int, int)} ) the type field is ignored.
@@ -193,6 +222,22 @@ public class TlvBufferUtils {
}
/**
+ * Copies a byte array into the TLV - without a type or a length.
+ *
+ * @param array The array to be copied (in full) into the TLV structure.
+ * @return The constructor to facilitate chaining
+ * {@code ctr.putXXX(..).putXXX(..)}.
+ */
+ public TlvConstructor putRawByteArray(@Nullable byte[] array) {
+ if (array == null) return this;
+
+ checkRawLength(array.length);
+ System.arraycopy(array, 0, mArray, mPosition, array.length);
+ mPosition += array.length;
+ return this;
+ }
+
+ /**
* Places a zero length element (i.e. Length field = 0) into the TLV.
* For an LV formatted structure (i.e. typeLength=0 in
* {@link TlvConstructor TlvConstructor(int, int)} ) the type field is
@@ -221,7 +266,7 @@ public class TlvBufferUtils {
public TlvConstructor putShort(int type, short data) {
checkLength(2);
addHeader(type, 2);
- Memory.pokeShort(mArray, mPosition, data, ByteOrder.BIG_ENDIAN);
+ Memory.pokeShort(mArray, mPosition, data, mByteOrder);
mPosition += 2;
return this;
}
@@ -239,7 +284,7 @@ public class TlvBufferUtils {
public TlvConstructor putInt(int type, int data) {
checkLength(4);
addHeader(type, 4);
- Memory.pokeInt(mArray, mPosition, data, ByteOrder.BIG_ENDIAN);
+ Memory.pokeInt(mArray, mPosition, data, mByteOrder);
mPosition += 4;
return this;
}
@@ -294,18 +339,24 @@ public class TlvBufferUtils {
}
}
+ private void checkRawLength(int dataLength) {
+ if (mPosition + dataLength > mArrayLength) {
+ throw new BufferOverflowException();
+ }
+ }
+
private void addHeader(int type, int length) {
if (mTypeSize == 1) {
mArray[mPosition] = (byte) type;
} else if (mTypeSize == 2) {
- Memory.pokeShort(mArray, mPosition, (short) type, ByteOrder.BIG_ENDIAN);
+ Memory.pokeShort(mArray, mPosition, (short) type, mByteOrder);
}
mPosition += mTypeSize;
if (mLengthSize == 1) {
mArray[mPosition] = (byte) length;
} else if (mLengthSize == 2) {
- Memory.pokeShort(mArray, mPosition, (short) length, ByteOrder.BIG_ENDIAN);
+ Memory.pokeShort(mArray, mPosition, (short) length, mByteOrder);
}
mPosition += mLengthSize;
}
@@ -330,13 +381,19 @@ public class TlvBufferUtils {
public int length;
/**
+ * Control of the endianess of the TLV element - true for big-endian, false for little-
+ * endian.
+ */
+ public ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;
+
+ /**
* The Value (V) field - a raw byte array representing the current TLV
* element where the entry starts at {@link TlvElement#offset}.
*/
- public byte[] refArray;
+ private byte[] mRefArray;
/**
- * The offset to be used into {@link TlvElement#refArray} to access the
+ * The offset to be used into {@link TlvElement#mRefArray} to access the
* raw data representing the current TLV element.
*/
public int offset;
@@ -344,7 +401,7 @@ public class TlvBufferUtils {
private TlvElement(int type, int length, @Nullable byte[] refArray, int offset) {
this.type = type;
this.length = length;
- this.refArray = refArray;
+ mRefArray = refArray;
this.offset = offset;
if (offset + length > refArray.length) {
@@ -353,6 +410,15 @@ public class TlvBufferUtils {
}
/**
+ * Return the raw byte array of the Value (V) field.
+ *
+ * @return The Value (V) field as a byte array.
+ */
+ public byte[] getRawData() {
+ return Arrays.copyOfRange(mRefArray, offset, offset + length);
+ }
+
+ /**
* Utility function to return a byte representation of a TLV element of
* length 1. Note: an attempt to call this function on a TLV item whose
* {@link TlvElement#length} is != 1 will result in an exception.
@@ -364,7 +430,7 @@ public class TlvBufferUtils {
throw new IllegalArgumentException(
"Accesing a byte from a TLV element of length " + length);
}
- return refArray[offset];
+ return mRefArray[offset];
}
/**
@@ -379,7 +445,7 @@ public class TlvBufferUtils {
throw new IllegalArgumentException(
"Accesing a short from a TLV element of length " + length);
}
- return Memory.peekShort(refArray, offset, ByteOrder.BIG_ENDIAN);
+ return Memory.peekShort(mRefArray, offset, byteOrder);
}
/**
@@ -394,7 +460,7 @@ public class TlvBufferUtils {
throw new IllegalArgumentException(
"Accesing an int from a TLV element of length " + length);
}
- return Memory.peekInt(refArray, offset, ByteOrder.BIG_ENDIAN);
+ return Memory.peekInt(mRefArray, offset, byteOrder);
}
/**
@@ -403,7 +469,7 @@ public class TlvBufferUtils {
* @return String repersentation of the current TLV element.
*/
public String getString() {
- return new String(refArray, offset, length);
+ return new String(mRefArray, offset, length);
}
}
@@ -413,6 +479,7 @@ public class TlvBufferUtils {
public static class TlvIterable implements Iterable<TlvElement> {
private int mTypeSize;
private int mLengthSize;
+ private ByteOrder mByteOrder = ByteOrder.BIG_ENDIAN;
private byte[] mArray;
private int mArrayLength;
@@ -440,6 +507,13 @@ public class TlvBufferUtils {
}
/**
+ * Configure the TLV iterator to use little-endian byte ordering.
+ */
+ public void setByteOrder(ByteOrder byteOrder) {
+ mByteOrder = byteOrder;
+ }
+
+ /**
* Prints out a parsed representation of the TLV-formatted byte array.
* Whenever possible bytes, shorts, and integer are printed out (for
* fields whose length is 1, 2, or 4 respectively).
@@ -486,7 +560,7 @@ public class TlvBufferUtils {
public List<byte[]> toList() {
List<byte[]> list = new ArrayList<>();
for (TlvElement tlv : this) {
- list.add(Arrays.copyOfRange(tlv.refArray, tlv.offset, tlv.offset + tlv.length));
+ list.add(Arrays.copyOfRange(tlv.mRefArray, tlv.offset, tlv.offset + tlv.length));
}
return list;
@@ -516,7 +590,7 @@ public class TlvBufferUtils {
if (mTypeSize == 1) {
type = mArray[mOffset];
} else if (mTypeSize == 2) {
- type = Memory.peekShort(mArray, mOffset, ByteOrder.BIG_ENDIAN);
+ type = Memory.peekShort(mArray, mOffset, mByteOrder);
}
mOffset += mTypeSize;
@@ -524,11 +598,12 @@ public class TlvBufferUtils {
if (mLengthSize == 1) {
length = mArray[mOffset];
} else if (mLengthSize == 2) {
- length = Memory.peekShort(mArray, mOffset, ByteOrder.BIG_ENDIAN);
+ length = Memory.peekShort(mArray, mOffset, mByteOrder);
}
mOffset += mLengthSize;
TlvElement tlv = new TlvElement(type, length, mArray, mOffset);
+ tlv.byteOrder = mByteOrder;
mOffset += length;
return tlv;
}
@@ -543,7 +618,8 @@ public class TlvBufferUtils {
/**
* Validates that a (T)LV array is constructed correctly. I.e. that its specified Length
- * fields correctly fill the specified length (and do not overshoot).
+ * fields correctly fill the specified length (and do not overshoot). Uses big-endian
+ * byte ordering.
*
* @param array The (T)LV array to verify.
* @param typeSize The size (in bytes) of the type field. Valid values are 0, 1, or 2.
@@ -551,6 +627,22 @@ public class TlvBufferUtils {
* @return A boolean indicating whether the array is valid (true) or invalid (false).
*/
public static boolean isValid(@Nullable byte[] array, int typeSize, int lengthSize) {
+ return isValidEndian(array, typeSize, lengthSize, ByteOrder.BIG_ENDIAN);
+ }
+
+ /**
+ * Validates that a (T)LV array is constructed correctly. I.e. that its specified Length
+ * fields correctly fill the specified length (and do not overshoot).
+ *
+ * @param array The (T)LV array to verify.
+ * @param typeSize The size (in bytes) of the type field. Valid values are 0, 1, or 2.
+ * @param lengthSize The size (in bytes) of the length field. Valid values are 1 or 2.
+ * @param byteOrder The endianness of the byte array: {@link ByteOrder#BIG_ENDIAN} or
+ * {@link ByteOrder#LITTLE_ENDIAN}.
+ * @return A boolean indicating whether the array is valid (true) or invalid (false).
+ */
+ public static boolean isValidEndian(@Nullable byte[] array, int typeSize, int lengthSize,
+ ByteOrder byteOrder) {
if (typeSize < 0 || typeSize > 2) {
throw new IllegalArgumentException(
"Invalid arguments - typeSize must be 0, 1, or 2: typeSize=" + typeSize);
@@ -569,8 +661,7 @@ public class TlvBufferUtils {
if (lengthSize == 1) {
nextTlvIndex += lengthSize + array[nextTlvIndex];
} else {
- nextTlvIndex += lengthSize + Memory.peekShort(array, nextTlvIndex,
- ByteOrder.BIG_ENDIAN);
+ nextTlvIndex += lengthSize + Memory.peekShort(array, nextTlvIndex, byteOrder);
}
}
diff --git a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
index 83affed0b4e0..971aa8e05df2 100644
--- a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
@@ -28,6 +28,7 @@ import java.nio.BufferOverflowException;
import java.util.ArrayList;
import java.util.List;
+
/**
* Unit test harness for TlvBufferUtils class.
*/
@@ -69,6 +70,24 @@ public class TlvBufferUtilsTest {
}
/**
+ * Validate that re-using a TLV by any of the reallocation method resets it completely.
+ */
+ @Test
+ public void testTlvReuse() {
+ TlvBufferUtils.TlvConstructor tlv = new TlvBufferUtils.TlvConstructor(1, 1);
+
+ tlv.allocate(10);
+ tlv.putByte(0, (byte) 2);
+ tlv.putByte(1, (byte) 104);
+
+ collector.checkThat("initial", tlv.getArray(), equalTo(new byte[]{0, 1, 2, 1, 1, 104}));
+
+ tlv.allocate(8);
+ tlv.putByte(5, (byte) 7);
+ collector.checkThat("re-alloc", tlv.getArray(), equalTo(new byte[]{5, 1, 7}));
+ }
+
+ /**
* Verify that can build a valid TLV from a List of byte[].
*/
@Test
@@ -121,6 +140,23 @@ public class TlvBufferUtilsTest {
List<byte[]> data = new TlvBufferUtils.TlvIterable(0, 1, invalidTlv01).toList();
}
+ /**
+ * Validate the API which places raw bytes into the TLV (without a TL structure).
+ */
+ @Test
+ public void testRawPuts() {
+ TlvBufferUtils.TlvConstructor tlv = new TlvBufferUtils.TlvConstructor(1, 1);
+
+ tlv.allocate(10);
+ tlv.putByte(0, (byte) 2);
+ tlv.putRawByte((byte) 55);
+ tlv.putByte(1, (byte) 104);
+ tlv.putRawByteArray(new byte[]{66, 77});
+
+ collector.checkThat("data", tlv.getArray(),
+ equalTo(new byte[]{0, 1, 2, 55, 1, 1, 104, 66, 77}));
+ }
+
@Test
public void testTlvIterate() {
final String ascii = "ABC";
@@ -163,6 +199,7 @@ public class TlvBufferUtilsTest {
tlv02.putByte(0, (byte) 2);
tlv02.putString(0, ascii);
tlv02.putString(0, nonAscii);
+ tlv02.putByteArray(0, new byte[]{5, 4, 3, 2, 1});
TlvBufferUtils.TlvIterable tlv02It = new TlvBufferUtils.TlvIterable(0, 2, tlv02.getArray());
count = 0;
@@ -181,6 +218,11 @@ public class TlvBufferUtilsTest {
equalTo(nonAscii.getBytes().length));
collector.checkThat("tlv02-correct-iteration-DATA",
tlv.getString().equals(nonAscii), equalTo(true));
+ } else if (count == 3) {
+ collector.checkThat("tlv02-correct-iteration-mLength", tlv.length,
+ equalTo(5));
+ collector.checkThat("tlv02-correct-iteration-DATA", tlv.getRawData(),
+ equalTo(new byte[]{5, 4, 3, 2, 1}));
} else {
collector.checkThat("Invalid number of iterations in loop - tlv02", true,
equalTo(false));
@@ -188,7 +230,7 @@ public class TlvBufferUtilsTest {
++count;
}
collector.checkThat("Invalid number of iterations outside loop - tlv02", count,
- equalTo(3));
+ equalTo(4));
collector.checkThat("tlv22-valid",
TlvBufferUtils.isValid(tlv22.getArray(), 2, 2),
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 6da6d4adeb62..3cc96bf2c795 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -1614,23 +1614,31 @@ public class WifiAwareManagerTest {
assertEquals(cap.hashCode(), rereadCap.hashCode());
}
- // PeerHandle tests
+ // ParcelablePeerHandle tests
+ /**
+ * Verify parceling of ParcelablePeerHandle and interoperability with PeerHandle.
+ */
@Test
- public void testPeerHandleParcel() {
+ public void testParcelablePeerHandleParcel() {
final PeerHandle peerHandle = new PeerHandle(5);
+ final ParcelablePeerHandle parcelablePeerHandle = new ParcelablePeerHandle(peerHandle);
Parcel parcelW = Parcel.obtain();
- peerHandle.writeToParcel(parcelW, 0);
+ parcelablePeerHandle.writeToParcel(parcelW, 0);
byte[] bytes = parcelW.marshall();
parcelW.recycle();
Parcel parcelR = Parcel.obtain();
parcelR.unmarshall(bytes, 0, bytes.length);
parcelR.setDataPosition(0);
- PeerHandle rereadPeerHandle = PeerHandle.CREATOR.createFromParcel(parcelR);
+ ParcelablePeerHandle rereadParcelablePeerHandle =
+ ParcelablePeerHandle.CREATOR.createFromParcel(parcelR);
+
+ assertEquals(peerHandle, rereadParcelablePeerHandle);
+ assertEquals(peerHandle.hashCode(), rereadParcelablePeerHandle.hashCode());
+ assertEquals(parcelablePeerHandle, rereadParcelablePeerHandle);
+ assertEquals(parcelablePeerHandle.hashCode(), rereadParcelablePeerHandle.hashCode());
- assertEquals(peerHandle, rereadPeerHandle);
- assertEquals(peerHandle.hashCode(), rereadPeerHandle.hashCode());
}
}