summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp5
-rw-r--r--Android.mk4
-rw-r--r--api/current.txt180
-rw-r--r--api/removed.txt6
-rw-r--r--api/system-current.txt31
-rw-r--r--api/test-current.txt11
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java2
-rw-r--r--cmds/am/src/com/android/commands/am/Instrument.java8
-rw-r--r--cmds/incident_helper/OWNERS2
-rw-r--r--cmds/incident_helper/src/parsers/CpuFreqParser.cpp12
-rw-r--r--cmds/incident_helper/src/parsers/CpuInfoParser.cpp44
-rw-r--r--cmds/incident_helper/src/parsers/KernelWakesParser.cpp6
-rw-r--r--cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp24
-rw-r--r--cmds/incident_helper/src/parsers/ProcrankParser.cpp16
-rw-r--r--cmds/incident_helper/src/parsers/PsParser.cpp8
-rw-r--r--cmds/incident_helper/tests/CpuFreqParser_test.cpp12
-rw-r--r--cmds/incident_helper/tests/CpuInfoParser_test.cpp34
-rw-r--r--cmds/incident_helper/tests/KernelWakesParser_test.cpp12
-rw-r--r--cmds/incident_helper/tests/PageTypeInfoParser_test.cpp10
-rw-r--r--cmds/incident_helper/tests/ProcrankParser_test.cpp16
-rw-r--r--cmds/incident_helper/tests/PsParser_test.cpp72
-rw-r--r--cmds/incidentd/.clang-format17
-rw-r--r--cmds/incidentd/Android.mk5
-rw-r--r--cmds/incidentd/OWNERS2
-rw-r--r--cmds/incidentd/README.md6
-rw-r--r--cmds/incidentd/src/FdBuffer.cpp84
-rw-r--r--cmds/incidentd/src/FdBuffer.h9
-rw-r--r--cmds/incidentd/src/IncidentService.cpp244
-rw-r--r--cmds/incidentd/src/IncidentService.h30
-rw-r--r--cmds/incidentd/src/Log.h (renamed from cmds/incidentd/src/io_util.cpp)40
-rw-r--r--cmds/incidentd/src/Privacy.cpp52
-rw-r--r--cmds/incidentd/src/Privacy.h10
-rw-r--r--cmds/incidentd/src/PrivacyBuffer.cpp75
-rw-r--r--cmds/incidentd/src/PrivacyBuffer.h11
-rw-r--r--cmds/incidentd/src/Reporter.cpp134
-rw-r--r--cmds/incidentd/src/Reporter.h42
-rw-r--r--cmds/incidentd/src/Section.cpp387
-rw-r--r--cmds/incidentd/src/Section.h46
-rw-r--r--cmds/incidentd/src/incidentd_util.cpp53
-rw-r--r--cmds/incidentd/src/incidentd_util.h (renamed from cmds/incidentd/src/io_util.h)19
-rw-r--r--cmds/incidentd/src/main.cpp12
-rw-r--r--cmds/incidentd/src/report_directory.cpp35
-rw-r--r--cmds/incidentd/src/report_directory.h10
-rw-r--r--cmds/incidentd/src/section_list.h6
-rw-r--r--cmds/incidentd/tests/FdBuffer_test.cpp37
-rw-r--r--cmds/incidentd/tests/PrivacyBuffer_test.cpp73
-rw-r--r--cmds/incidentd/tests/Reporter_test.cpp53
-rw-r--r--cmds/incidentd/tests/Section_test.cpp53
-rw-r--r--cmds/incidentd/tests/section_list.cpp22
-rw-r--r--cmds/statsd/Android.mk4
-rw-r--r--cmds/statsd/OWNERS6
-rw-r--r--cmds/statsd/src/FieldValue.cpp20
-rw-r--r--cmds/statsd/src/FieldValue.h21
-rw-r--r--cmds/statsd/src/HashableDimensionKey.cpp2
-rw-r--r--cmds/statsd/src/StatsLogProcessor.cpp32
-rw-r--r--cmds/statsd/src/StatsService.cpp51
-rw-r--r--cmds/statsd/src/StatsService.h5
-rw-r--r--cmds/statsd/src/atoms.proto92
-rw-r--r--cmds/statsd/src/config/ConfigManager.cpp120
-rw-r--r--cmds/statsd/src/config/ConfigManager.h5
-rw-r--r--cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp8
-rw-r--r--cmds/statsd/src/external/CpuTimePerUidPuller.cpp7
-rw-r--r--cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp7
-rw-r--r--cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp6
-rw-r--r--cmds/statsd/src/external/ResourceHealthManagerPuller.cpp10
-rw-r--r--cmds/statsd/src/external/StatsCompanionServicePuller.cpp5
-rw-r--r--cmds/statsd/src/external/StatsPuller.cpp3
-rw-r--r--cmds/statsd/src/external/StatsPullerManagerImpl.cpp13
-rw-r--r--cmds/statsd/src/external/SubsystemSleepStatePuller.cpp21
-rw-r--r--cmds/statsd/src/guardrail/StatsdStats.cpp33
-rw-r--r--cmds/statsd/src/guardrail/StatsdStats.h1
-rw-r--r--cmds/statsd/src/logd/LogEvent.cpp59
-rw-r--r--cmds/statsd/src/logd/LogEvent.h27
-rw-r--r--cmds/statsd/src/matchers/matcher_util.cpp25
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.cpp15
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.cpp34
-rw-r--r--cmds/statsd/src/metrics/EventMetricProducer.cpp9
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.cpp20
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.cpp2
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.h6
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.cpp21
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.cpp12
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.h4
-rw-r--r--cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp1
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.cpp8
-rw-r--r--cmds/statsd/src/packages/UidMap.cpp21
-rw-r--r--cmds/statsd/src/stats_log.proto26
-rw-r--r--cmds/statsd/src/stats_log_util.cpp47
-rw-r--r--cmds/statsd/src/stats_log_util.h24
-rw-r--r--cmds/statsd/src/storage/StorageManager.cpp3
-rw-r--r--cmds/statsd/tests/e2e/Attribution_e2e_test.cpp28
-rw-r--r--cmds/statsd/tests/e2e/DimensionInCondition_e2e_test.cpp110
-rw-r--r--cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp12
-rw-r--r--cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp4
-rw-r--r--cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp8
-rw-r--r--cmds/statsd/tests/guardrail/StatsdStats_test.cpp2
-rw-r--r--cmds/statsd/tests/metrics/CountMetricProducer_test.cpp26
-rw-r--r--cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp55
-rw-r--r--cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp9
-rw-r--r--cmds/statsd/tests/metrics/OringDurationTracker_test.cpp16
-rw-r--r--cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp16
-rw-r--r--cmds/statsd/tests/statsd_test_util.cpp2
-rw-r--r--cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java14
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java14
-rw-r--r--config/hiddenapi-light-greylist.txt309
-rw-r--r--core/java/Android.bp30
-rw-r--r--core/java/android/annotation/OWNERS1
-rw-r--r--core/java/android/annotation/RequiresFeature.java45
-rw-r--r--core/java/android/annotation/SystemService.java9
-rw-r--r--core/java/android/app/Activity.java39
-rw-r--r--core/java/android/app/ActivityManager.java25
-rw-r--r--core/java/android/app/ActivityManagerInternal.java5
-rw-r--r--core/java/android/app/ActivityOptions.java5
-rw-r--r--core/java/android/app/ActivityThread.java56
-rw-r--r--core/java/android/app/AppOpsManager.java1
-rw-r--r--core/java/android/app/IActivityManager.aidl32
-rw-r--r--core/java/android/app/IAlarmManager.aidl1
-rw-r--r--core/java/android/app/Notification.java21
-rw-r--r--core/java/android/app/ProcessMemoryState.java88
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java2
-rw-r--r--core/java/android/app/admin/FreezeInterval.java6
-rw-r--r--core/java/android/app/admin/SecurityLog.java23
-rw-r--r--core/java/android/app/admin/SecurityLogTags.logtags4
-rw-r--r--core/java/android/app/admin/SystemUpdatePolicy.java175
-rw-r--r--core/java/android/app/assist/AssistStructure.java20
-rw-r--r--core/java/android/app/backup/OWNERS7
-rw-r--r--core/java/android/app/servertransaction/ActivityLifecycleItem.java5
-rw-r--r--core/java/android/app/servertransaction/DestroyActivityItem.java1
-rw-r--r--core/java/android/app/servertransaction/PauseActivityItem.java1
-rw-r--r--core/java/android/app/servertransaction/ResumeActivityItem.java1
-rw-r--r--core/java/android/app/servertransaction/StopActivityItem.java1
-rw-r--r--core/java/android/appwidget/AppWidgetManager.java3
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java6
-rw-r--r--core/java/android/bluetooth/BluetoothHearingAid.java693
-rw-r--r--core/java/android/bluetooth/BluetoothManager.java3
-rw-r--r--core/java/android/bluetooth/BluetoothProfile.java9
-rw-r--r--core/java/android/bluetooth/BluetoothUuid.java3
-rw-r--r--core/java/android/content/ContextWrapper.java6
-rw-r--r--core/java/android/content/om/IOverlayManager.aidl25
-rw-r--r--core/java/android/content/om/OverlayInfo.java27
-rw-r--r--core/java/android/content/pm/PackageInfo.java9
-rw-r--r--core/java/android/content/pm/PackageManager.java10
-rw-r--r--core/java/android/content/pm/PackageParser.java6
-rw-r--r--core/java/android/content/res/ResourcesImpl.java26
-rw-r--r--core/java/android/database/sqlite/SQLiteOpenHelper.java29
-rw-r--r--core/java/android/hardware/Camera.java11
-rw-r--r--core/java/android/hardware/ConsumerIrManager.java3
-rw-r--r--core/java/android/hardware/OWNERS7
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java8
-rw-r--r--core/java/android/hardware/camera2/CameraDevice.java11
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java13
-rw-r--r--core/java/android/hardware/camera2/OWNERS6
-rw-r--r--core/java/android/hardware/camera2/params/OutputConfiguration.java8
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java3
-rw-r--r--core/java/android/hardware/hdmi/HdmiControlManager.java3
-rw-r--r--core/java/android/hardware/radio/RadioManager.java3
-rw-r--r--core/java/android/hardware/usb/UsbDeviceConnection.java14
-rw-r--r--core/java/android/hardware/usb/UsbManager.java10
-rw-r--r--core/java/android/hardware/usb/UsbRequest.java26
-rw-r--r--core/java/android/net/ConnectivityManager.java48
-rw-r--r--core/java/android/net/IpSecConfig.java19
-rw-r--r--core/java/android/net/IpSecTransform.java18
-rw-r--r--core/java/android/net/NetworkCapabilities.java30
-rw-r--r--core/java/android/net/OWNERS2
-rw-r--r--core/java/android/os/BatteryStats.java8
-rw-r--r--core/java/android/os/BestClock.java58
-rw-r--r--core/java/android/os/Binder.java26
-rw-r--r--core/java/android/os/ChildZygoteProcess.java44
-rw-r--r--core/java/android/os/HwBinder.java28
-rw-r--r--core/java/android/os/IUserManager.aidl1
-rw-r--r--core/java/android/os/SimpleClock.java53
-rw-r--r--core/java/android/os/SystemClock.java107
-rw-r--r--core/java/android/os/UserManager.java12
-rw-r--r--core/java/android/os/ZygoteProcess.java55
-rw-r--r--core/java/android/os/storage/StorageResultCode.java75
-rw-r--r--core/java/android/print/PrintManager.java3
-rw-r--r--core/java/android/provider/Settings.java104
-rw-r--r--core/java/android/provider/SettingsSlicesContract.java4
-rw-r--r--core/java/android/security/IConfirmationPromptCallback.aidl27
-rw-r--r--core/java/android/security/IKeystoreService.aidl87
-rw-r--r--core/java/android/security/KeystoreArguments.aidl20
-rw-r--r--core/java/android/security/keymaster/KeymasterArguments.aidl20
-rw-r--r--core/java/android/security/keymaster/KeymasterBlob.aidl20
-rw-r--r--core/java/android/security/keymaster/KeymasterCertificateChain.aidl20
-rw-r--r--core/java/android/security/keymaster/KeymasterDefs.java3
-rw-r--r--core/java/android/security/keymaster/OperationResult.aidl20
-rw-r--r--core/java/android/security/keystore/OWNERS4
-rw-r--r--core/java/android/service/autofill/AutofillServiceInfo.java35
-rw-r--r--core/java/android/service/autofill/DateTransformation.java2
-rw-r--r--core/java/android/service/autofill/DateValueSanitizer.java2
-rw-r--r--core/java/android/service/autofill/FieldClassification.java18
-rw-r--r--core/java/android/service/autofill/FillContext.java24
-rw-r--r--core/java/android/service/autofill/UserData.java155
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java4
-rw-r--r--core/java/android/speech/tts/SynthesisPlaybackQueueItem.java22
-rw-r--r--core/java/android/text/OWNERS2
-rw-r--r--core/java/android/text/style/TypefaceSpan.java109
-rw-r--r--core/java/android/text/util/Linkify.java14
-rw-r--r--core/java/android/transition/TransitionUtils.java25
-rw-r--r--core/java/android/util/ExceptionUtils.java14
-rw-r--r--core/java/android/util/OWNERS2
-rw-r--r--core/java/android/util/StatsLog.java7
-rw-r--r--core/java/android/view/DisplayCutout.java10
-rw-r--r--core/java/android/view/RenderNodeAnimator.java2
-rw-r--r--core/java/android/view/ThreadedRenderer.java9
-rw-r--r--core/java/android/view/View.java10
-rw-r--r--core/java/android/view/ViewDebug.java21
-rw-r--r--core/java/android/view/WindowInfo.java7
-rw-r--r--core/java/android/view/WindowManager.java7
-rw-r--r--core/java/android/view/animation/AnimationUtils.java34
-rw-r--r--core/java/android/view/autofill/AutofillId.java1
-rw-r--r--core/java/android/view/autofill/AutofillManager.java127
-rw-r--r--core/java/android/view/autofill/AutofillPopupWindow.java19
-rw-r--r--core/java/android/view/autofill/IAutoFillManager.aidl4
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java3
-rw-r--r--core/java/android/view/textclassifier/SystemTextClassifier.java9
-rw-r--r--core/java/android/view/textclassifier/TextClassifier.java27
-rw-r--r--core/java/android/view/textclassifier/TextClassifierConstants.java36
-rw-r--r--core/java/android/view/textclassifier/TextClassifierImpl.java15
-rw-r--r--core/java/android/view/textclassifier/TextLinks.java7
-rw-r--r--core/java/android/webkit/TracingConfig.java259
-rw-r--r--core/java/android/webkit/TracingController.java78
-rw-r--r--core/java/android/webkit/TracingFileOutputStream.java63
-rw-r--r--core/java/android/widget/LinearLayout.java4
-rw-r--r--core/java/android/widget/OWNERS2
-rw-r--r--core/java/android/widget/PopupWindow.java2
-rw-r--r--core/java/android/widget/RadioGroup.java10
-rw-r--r--core/java/android/widget/TextView.java24
-rw-r--r--core/java/com/android/internal/app/ResolverListController.java75
-rw-r--r--core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java7
-rw-r--r--core/java/com/android/internal/notification/SystemNotificationChannels.java6
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java252
-rw-r--r--core/java/com/android/internal/os/KernelSingleUidTimeReader.java38
-rw-r--r--core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java2
-rw-r--r--core/java/com/android/internal/os/KernelUidCpuTimeReader.java12
-rw-r--r--core/java/com/android/internal/os/RuntimeInit.java2
-rw-r--r--core/java/com/android/internal/os/WebViewZygoteInit.java2
-rw-r--r--core/java/com/android/internal/os/Zygote.java26
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java43
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java25
-rw-r--r--core/java/com/android/internal/os/ZygoteServer.java41
-rw-r--r--core/java/com/android/internal/print/DumpUtils.java3
-rw-r--r--core/java/com/android/internal/util/OWNERS24
-rw-r--r--core/jni/OWNERS12
-rw-r--r--core/jni/android_hardware_Camera.cpp1
-rw-r--r--core/jni/android_util_Binder.cpp3
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp24
-rw-r--r--core/jni/fd_utils.cpp8
-rw-r--r--core/proto/android/net/OWNERS5
-rw-r--r--core/proto/android/os/cpufreq.proto26
-rw-r--r--core/proto/android/os/cpuinfo.proto3
-rw-r--r--core/proto/android/os/incident.proto20
-rw-r--r--core/proto/android/os/kernelwake.proto35
-rw-r--r--core/proto/android/os/pagetypeinfo.proto51
-rw-r--r--core/proto/android/os/procrank.proto93
-rw-r--r--core/proto/android/os/ps.proto2
-rw-r--r--core/proto/android/providers/settings.proto6
-rw-r--r--core/res/AndroidManifest.xml4
-rw-r--r--core/res/res/color-watch/btn_watch_default_dark.xml (renamed from core/res/res/values-watch/colors_material.xml)13
-rw-r--r--core/res/res/color-watch/switch_thumb_watch_default_dark.xml (renamed from core/res/res/color/watch_switch_thumb_color_material.xml)4
-rw-r--r--core/res/res/color-watch/switch_track_watch_default_dark.xml (renamed from core/res/res/color/watch_switch_track_color_material.xml)6
-rw-r--r--core/res/res/drawable-watch/switch_thumb_watch_default_dark_anim.xml (renamed from core/res/res/drawable/watch_switch_thumb_material_anim.xml)0
-rw-r--r--core/res/res/drawable/ic_settings_24dp.xml8
-rw-r--r--core/res/res/drawable/ic_signal_cellular_alt_24px.xml40
-rw-r--r--core/res/res/layout-watch/preference_widget_switch.xml6
-rw-r--r--core/res/res/layout/autofill_dataset_picker_fullscreen.xml48
-rw-r--r--core/res/res/values-da/strings.xml73
-rw-r--r--core/res/res/values-eu/strings.xml71
-rw-r--r--core/res/res/values-fr-rCA/strings.xml35
-rw-r--r--core/res/res/values-hy/strings.xml73
-rw-r--r--core/res/res/values-mcc302-mnc220/config.xml2
-rw-r--r--core/res/res/values-mcc302-mnc221/config.xml2
-rw-r--r--core/res/res/values-television/dimens.xml4
-rw-r--r--core/res/res/values-uz/strings.xml35
-rw-r--r--core/res/res/values-watch/colors_device_defaults.xml96
-rw-r--r--core/res/res/values/attrs.xml4
-rw-r--r--core/res/res/values/attrs_manifest.xml3
-rw-r--r--core/res/res/values/colors_material.xml6
-rw-r--r--core/res/res/values/config.xml16
-rw-r--r--core/res/res/values/dimens.xml3
-rw-r--r--core/res/res/values/public.xml1
-rw-r--r--core/res/res/values/strings.xml24
-rw-r--r--core/res/res/values/symbols.xml23
-rw-r--r--core/res/res/values/themes.xml67
-rw-r--r--core/res/res/values/themes_holo.xml321
-rw-r--r--core/res/res/values/themes_material.xml1
-rw-r--r--core/res/res/xml/default_zen_mode_config.xml2
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java9
-rw-r--r--core/tests/coretests/src/android/text/OWNERS4
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java23
-rw-r--r--core/tests/coretests/src/android/widget/TextViewActivityTest.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java46
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java7
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java40
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java24
-rw-r--r--core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java18
-rw-r--r--core/tests/featureflagtests/OWNERS2
-rw-r--r--core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk7
-rw-r--r--core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp5
-rw-r--r--core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk8
-rw-r--r--core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp5
-rw-r--r--core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk6
-rw-r--r--core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp5
-rw-r--r--docs/html/reference/images/text/style/typefacespan.pngbin7749 -> 8753 bytes
-rw-r--r--graphics/java/android/graphics/ImageDecoder.java65
-rw-r--r--graphics/java/android/graphics/drawable/NinePatchDrawable.java3
-rw-r--r--graphics/java/android/graphics/drawable/RippleBackground.java7
-rw-r--r--keystore/java/android/security/KeyStore.java23
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java19
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java16
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreSpi.java16
-rw-r--r--keystore/java/android/security/keystore/KeyGenParameterSpec.java40
-rw-r--r--keystore/java/android/security/keystore/KeyProtection.java56
-rw-r--r--keystore/java/android/security/keystore/KeymasterUtils.java40
-rw-r--r--keystore/java/android/security/keystore/UserAuthArgs.java38
-rw-r--r--libs/incident/Android.mk1
-rw-r--r--libs/incident/proto/android/os/metadata.proto63
-rw-r--r--location/java/android/location/LocationManager.java3
-rw-r--r--media/OWNERS4
-rw-r--r--media/java/android/media/AudioManager.java111
-rw-r--r--media/java/android/media/DataSourceDesc.java14
-rw-r--r--media/java/android/media/IAudioServerStateDispatcher.aidl (renamed from core/java/android/security/keymaster/ExportResult.aidl)16
-rw-r--r--media/java/android/media/IAudioService.aidl8
-rw-r--r--media/java/android/media/MediaPlayer2.java13
-rw-r--r--media/java/android/media/MediaPlayer2Impl.java478
-rw-r--r--media/java/android/media/MediaRecorder.java3
-rw-r--r--media/java/android/media/audiopolicy/AudioPolicy.java1
-rw-r--r--media/java/android/media/midi/MidiManager.java3
-rw-r--r--media/java/android/media/session/MediaSession.java17
-rw-r--r--media/jni/android_media_MediaDrm.cpp82
-rw-r--r--media/jni/android_media_MediaPlayer2.cpp97
-rw-r--r--native/android/OWNERS11
-rw-r--r--packages/CarrierDefaultApp/OWNERS12
-rw-r--r--packages/DefaultContainerService/AndroidManifest.xml3
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java50
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java5
-rw-r--r--packages/SettingsLib/res/drawable/ic_bt_hearing_aid.xml24
-rw-r--r--packages/SettingsLib/res/values/strings.xml7
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/Utils.java37
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java235
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java28
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java27
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java130
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java322
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java32
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java66
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java12
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java12
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java50
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java12
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java13
-rw-r--r--packages/SimAppDialog/Android.mk18
-rw-r--r--packages/SimAppDialog/AndroidManifest.xml (renamed from core/java/android/security/keymaster/KeyCharacteristics.aidl)21
-rw-r--r--packages/SimAppDialog/res/drawable/ic_signal_cellular_alt_rounded_24px.xml51
-rw-r--r--packages/SimAppDialog/res/drawable/placeholder.xml44
-rw-r--r--packages/SimAppDialog/res/layout/install_carrier_app_activity.xml57
-rw-r--r--packages/SimAppDialog/res/layout/install_carrier_app_footer.xml43
-rw-r--r--packages/SimAppDialog/res/values/strings.xml36
-rw-r--r--packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java95
-rw-r--r--packages/SystemUI/OWNERS6
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml17
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step.pngbin0 -> 1034 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step_dark.pngbin0 -> 681 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step.pngbin0 -> 1008 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step_dark.pngbin0 -> 695 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step.pngbin0 -> 895 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step_dark.pngbin0 -> 637 bytes
-rw-r--r--packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step.pngbin0 -> 875 bytes
-rw-r--r--packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step_dark.pngbin0 -> 649 bytes
-rw-r--r--packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step.pngbin0 -> 1087 bytes
-rw-r--r--packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step_dark.pngbin0 -> 762 bytes
-rw-r--r--packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step.pngbin0 -> 1661 bytes
-rw-r--r--packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step_dark.pngbin0 -> 1182 bytes
-rw-r--r--packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step.pngbin0 -> 1800 bytes
-rw-r--r--packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step_dark.pngbin0 -> 1548 bytes
-rw-r--r--packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step.pngbin0 -> 1010 bytes
-rw-r--r--packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step_dark.pngbin0 -> 710 bytes
-rw-r--r--packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step.pngbin0 -> 809 bytes
-rw-r--r--packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step_dark.pngbin0 -> 524 bytes
-rw-r--r--packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step.pngbin0 -> 1309 bytes
-rw-r--r--packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step_dark.pngbin0 -> 904 bytes
-rw-r--r--packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step.pngbin0 -> 1723 bytes
-rw-r--r--packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step_dark.pngbin0 -> 1596 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step.pngbin0 -> 800 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step_dark.pngbin0 -> 524 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step.pngbin0 -> 810 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step_dark.pngbin0 -> 522 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step.pngbin0 -> 744 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step_dark.pngbin0 -> 502 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step.pngbin0 -> 1317 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step_dark.pngbin0 -> 870 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step.pngbin0 -> 1302 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step_dark.pngbin0 -> 879 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step.pngbin0 -> 1065 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step_dark.pngbin0 -> 752 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step.pngbin0 -> 2062 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step_dark.pngbin0 -> 1306 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step.pngbin0 -> 1963 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step_dark.pngbin0 -> 1348 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step.pngbin0 -> 1631 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step_dark.pngbin0 -> 1142 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step.pngbin0 -> 1848 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step_dark.pngbin0 -> 1616 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step.pngbin0 -> 1740 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step_dark.pngbin0 -> 1554 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step.pngbin0 -> 1802 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step_dark.pngbin0 -> 1418 bytes
-rw-r--r--packages/SystemUI/res/drawable/car_ic_hvac.xml51
-rw-r--r--packages/SystemUI/res/drawable/car_ic_notification.xml28
-rw-r--r--packages/SystemUI/res/drawable/car_ic_overview.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_lock_lockdown.xml25
-rw-r--r--packages/SystemUI/res/drawable/logout_button_background.xml23
-rw-r--r--packages/SystemUI/res/drawable/smart_reply_button_background.xml4
-rw-r--r--packages/SystemUI/res/layout/car_facet_button.xml50
-rw-r--r--packages/SystemUI/res/layout/car_left_navigation_bar.xml99
-rw-r--r--packages/SystemUI/res/layout/car_navigation_bar.xml74
-rw-r--r--packages/SystemUI/res/layout/car_navigation_button.xml31
-rw-r--r--packages/SystemUI/res/layout/car_right_navigation_bar.xml101
-rw-r--r--packages/SystemUI/res/layout/menu_ime.xml9
-rw-r--r--packages/SystemUI/res/layout/notification_info.xml12
-rw-r--r--packages/SystemUI/res/layout/qs_footer_impl.xml23
-rw-r--r--packages/SystemUI/res/layout/screen_pinning_request_buttons.xml2
-rw-r--r--packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml2
-rw-r--r--packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml2
-rw-r--r--packages/SystemUI/res/layout/smart_reply_button.xml10
-rw-r--r--packages/SystemUI/res/layout/smart_reply_view.xml5
-rw-r--r--packages/SystemUI/res/values/arrays_tv.xml2
-rw-r--r--packages/SystemUI/res/values/attrs.xml6
-rw-r--r--packages/SystemUI/res/values/attrs_car.xml42
-rw-r--r--packages/SystemUI/res/values/colors.xml7
-rw-r--r--packages/SystemUI/res/values/config_car.xml5
-rw-r--r--packages/SystemUI/res/values/dimens.xml28
-rw-r--r--packages/SystemUI/res/values/strings.xml4
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl8
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl5
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java11
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java60
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java51
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java32
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/OverviewProxyService.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIService.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeService.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java161
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java114
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java407
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java108
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java107
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java188
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java116
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java266
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java61
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java458
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java290
-rw-r--r--packages/overlays/DisplayCutoutEmulationNarrowOverlay/AndroidManifest.xml4
-rw-r--r--packages/overlays/DisplayCutoutEmulationTallOverlay/AndroidManifest.xml4
-rw-r--r--packages/overlays/DisplayCutoutEmulationWideOverlay/AndroidManifest.xml4
-rw-r--r--pathmap.mk5
-rw-r--r--proto/src/metrics_constants.proto71
-rw-r--r--proto/src/system_messages.proto5
-rw-r--r--rs/OWNERS5
-rw-r--r--services/accessibility/java/com/android/server/accessibility/MagnificationController.java6
-rw-r--r--services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java18
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java121
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java50
-rw-r--r--services/autofill/java/com/android/server/autofill/Helper.java63
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java77
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/FillUi.java92
-rw-r--r--services/backup/OWNERS7
-rw-r--r--services/backup/java/com/android/server/backup/TransportManager.java11
-rw-r--r--services/backup/java/com/android/server/backup/transport/TransportClientManager.java29
-rw-r--r--services/core/java/com/android/server/AlarmManagerService.java42
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java53
-rw-r--r--services/core/java/com/android/server/InputMethodManagerService.java50
-rw-r--r--services/core/java/com/android/server/NetworkTimeUpdateService.java126
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java153
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java105
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java6
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerDebugConfig.java2
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java250
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java3
-rw-r--r--services/core/java/com/android/server/am/ActivityRecord.java8
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java24
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java40
-rw-r--r--services/core/java/com/android/server/am/ActivityStartController.java24
-rw-r--r--services/core/java/com/android/server/am/ActivityStarter.java3
-rw-r--r--services/core/java/com/android/server/am/BatteryExternalStatsWorker.java102
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java2
-rw-r--r--services/core/java/com/android/server/am/MemoryStatUtil.java10
-rw-r--r--services/core/java/com/android/server/am/PendingRemoteAnimationRegistry.java86
-rw-r--r--services/core/java/com/android/server/am/RecentsAnimation.java64
-rw-r--r--services/core/java/com/android/server/am/UriPermission.java4
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java255
-rw-r--r--services/core/java/com/android/server/audio/OWNERS2
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java11
-rw-r--r--services/core/java/com/android/server/content/ContentService.java15
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java93
-rw-r--r--services/core/java/com/android/server/content/SyncManagerConstants.java149
-rw-r--r--services/core/java/com/android/server/content/SyncOperation.java4
-rw-r--r--services/core/java/com/android/server/fingerprint/FingerprintService.java15
-rwxr-xr-x[-rw-r--r--]services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java3
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerService.java164
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerShellCommand.java19
-rw-r--r--services/core/java/com/android/server/job/JobServiceContext.java11
-rw-r--r--services/core/java/com/android/server/job/controllers/JobStatus.java9
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java177
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java44
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS4
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java6
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java109
-rw-r--r--services/core/java/com/android/server/media/OWNERS2
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java58
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java51
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java4
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java53
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerService.java23
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerServiceImpl.java25
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerSettings.java27
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerShellCommand.java33
-rw-r--r--services/core/java/com/android/server/pm/Installer.java11
-rw-r--r--services/core/java/com/android/server/pm/OtaDexoptService.java8
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java29
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java209
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java10
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java55
-rw-r--r--services/core/java/com/android/server/pm/PackageSettingBase.java24
-rw-r--r--services/core/java/com/android/server/pm/Settings.java42
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java17
-rw-r--r--services/core/java/com/android/server/pm/UserRestrictionsUtils.java10
-rw-r--r--services/core/java/com/android/server/pm/dex/DexManager.java7
-rw-r--r--services/core/java/com/android/server/pm/dex/DexoptOptions.java19
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java41
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java45
-rw-r--r--services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java13
-rw-r--r--services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java51
-rw-r--r--services/core/java/com/android/server/stats/OWNERS9
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java66
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java18
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java3
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java52
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java55
-rw-r--r--services/core/java/com/android/server/wm/RemoteAnimationController.java65
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java15
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimator.java17
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java18
-rw-r--r--services/core/jni/Android.bp2
-rw-r--r--services/core/jni/com_android_server_UsbAlsaJackDetector.cpp152
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp73
-rw-r--r--services/core/jni/onload.cpp2
-rw-r--r--services/java/com/android/server/SystemServer.java2
-rw-r--r--services/robotests/src/com/android/server/backup/TransportManagerTest.java55
-rw-r--r--services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java122
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java27
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java20
-rw-r--r--services/tests/servicestests/src/com/android/server/am/PendingRemoteAnimationRegistryTest.java103
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java142
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/OWNERS4
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java24
-rw-r--r--services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java47
-rw-r--r--services/tests/servicestests/src/com/android/server/testutils/TestHandler.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java84
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java16
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java49
-rw-r--r--services/usage/java/com/android/server/usage/AppIdleHistory.java66
-rw-r--r--services/usage/java/com/android/server/usage/AppStandbyController.java179
-rw-r--r--services/usb/OWNERS4
-rw-r--r--services/usb/java/com/android/server/usb/UsbAlsaDevice.java183
-rw-r--r--services/usb/java/com/android/server/usb/UsbAlsaJackDetector.java97
-rw-r--r--services/usb/java/com/android/server/usb/UsbAlsaManager.java97
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java2
-rw-r--r--telecomm/OWNERS6
-rw-r--r--telecomm/java/android/telecom/Call.java30
-rw-r--r--telecomm/java/android/telecom/Conference.java33
-rw-r--r--telecomm/java/android/telecom/Connection.java34
-rw-r--r--telecomm/java/android/telecom/ConnectionRequest.java7
-rw-r--r--telecomm/java/android/telecom/ConnectionService.java5
-rw-r--r--telephony/OWNERS (renamed from telephony/java/android/telephony/OWNERS)12
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthLte.java2
-rw-r--r--telephony/java/android/telephony/ServiceState.java46
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java107
-rw-r--r--telephony/java/android/telephony/ims/feature/ImsFeature.java2
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl24
-rw-r--r--tests/ActivityManagerPerfTests/README.txt45
-rw-r--r--tests/ActivityManagerPerfTests/test-app/Android.mk2
-rw-r--r--tests/ActivityManagerPerfTests/tests/Android.mk2
-rw-r--r--tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java392
-rw-r--r--tests/AppLaunchWear/Android.mk21
-rw-r--r--tests/AppLaunchWear/AndroidManifest.xml21
-rw-r--r--tests/AppLaunchWear/src/com/android/tests/applaunch/AppLaunch.java821
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/DrawIntoHwBitmapActivity.java11
-rw-r--r--tests/net/java/android/net/ConnectivityManagerTest.java11
-rw-r--r--tests/net/java/android/net/IpSecConfigTest.java43
-rw-r--r--tests/net/java/android/net/IpSecTransformTest.java62
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java36
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsServiceTest.java65
-rw-r--r--tools/aapt2/Debug.cpp67
-rw-r--r--tools/aapt2/Debug.h2
-rw-r--r--tools/aapt2/LoadedApk.cpp4
-rw-r--r--tools/aapt2/ResourceUtils.cpp4
-rw-r--r--tools/aapt2/ResourceUtils.h3
-rw-r--r--tools/aapt2/ResourceValues.cpp13
-rw-r--r--tools/aapt2/cmd/Convert.cpp1
-rw-r--r--tools/aapt2/cmd/Dump.cpp90
-rw-r--r--tools/aapt2/cmd/Link.cpp30
-rw-r--r--tools/aapt2/configuration/ConfigurationParser.cpp80
-rw-r--r--tools/aapt2/configuration/ConfigurationParser.internal.h34
-rw-r--r--tools/aapt2/configuration/ConfigurationParser_test.cpp129
-rw-r--r--tools/aapt2/configuration/aapt2.xsd5
-rw-r--r--tools/aapt2/configuration/example/config.xml24
-rw-r--r--tools/aapt2/link/XmlCompatVersioner_test.cpp12
-rw-r--r--tools/aapt2/optimize/MultiApkGenerator.cpp46
-rw-r--r--tools/aapt2/optimize/MultiApkGenerator.h5
-rw-r--r--tools/aapt2/test/Common.h115
-rw-r--r--tools/aapt2/xml/XmlDom.cpp11
-rw-r--r--tools/aapt2/xml/XmlDom_test.cpp31
-rw-r--r--tools/apilint/apilint.py42
-rw-r--r--tools/stats_log_api_gen/Android.bp1
-rw-r--r--tools/stats_log_api_gen/main.cpp3
-rw-r--r--wifi/OWNERS5
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java24
-rw-r--r--wifi/java/android/net/wifi/WpsInfo.java59
-rw-r--r--wifi/java/android/net/wifi/rtt/RangingRequest.java10
-rw-r--r--wifi/java/android/net/wifi/rtt/RangingResult.java4
654 files changed, 16933 insertions, 6806 deletions
diff --git a/Android.bp b/Android.bp
index 05fb3c083937..e65ba0f6a95f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -249,8 +249,7 @@ java_library {
"core/java/android/os/storage/IStorageEventListener.aidl",
"core/java/android/os/storage/IStorageShutdownObserver.aidl",
"core/java/android/os/storage/IObbActionListener.aidl",
- "core/java/android/security/IConfirmationPromptCallback.aidl",
- "core/java/android/security/IKeystoreService.aidl",
+ ":keystore_aidl",
"core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl",
"core/java/android/service/autofill/IAutoFillService.aidl",
"core/java/android/service/autofill/IAutofillFieldClassificationService.aidl",
@@ -425,6 +424,7 @@ java_library {
"media/java/android/media/IAudioFocusDispatcher.aidl",
"media/java/android/media/IAudioRoutesObserver.aidl",
"media/java/android/media/IAudioService.aidl",
+ "media/java/android/media/IAudioServerStateDispatcher.aidl",
"media/java/android/media/IMediaHTTPConnection.aidl",
"media/java/android/media/IMediaHTTPService.aidl",
"media/java/android/media/IMediaResourceMonitor.aidl",
@@ -642,6 +642,7 @@ java_library {
"system/netd/server/binder",
"system/vold/binder",
"system/bt/binder",
+ "system/security/keystore/binder",
],
},
diff --git a/Android.mk b/Android.mk
index f4208207e146..58e21ffd1617 100644
--- a/Android.mk
+++ b/Android.mk
@@ -793,6 +793,8 @@ LOCAL_SRC_FILES := \
$(call all-proto-files-under, core/proto) \
$(call all-proto-files-under, libs/incident/proto) \
$(call all-proto-files-under, cmds/statsd/src)
+# b/72714520
+LOCAL_ERROR_PRONE_FLAGS := -Xep:MissingOverride:OFF
include $(BUILD_HOST_JAVA_LIBRARY)
# ==== java proto device library (for test only) ==============================
@@ -804,7 +806,7 @@ LOCAL_PROTOC_FLAGS := \
-Iexternal/protobuf/src
LOCAL_PROTO_JAVA_OUTPUT_PARAMS := \
store_unknown_fields = true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart
+LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := \
$(call all-proto-files-under, core/proto) \
$(call all-proto-files-under, libs/incident/proto/android/os)
diff --git a/api/current.txt b/api/current.txt
index 04436d2f946f..7979d916bbd7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1468,6 +1468,7 @@ package android {
field public static final deprecated int unfocusedMonthDateColor = 16843588; // 0x1010344
field public static final int unselectedAlpha = 16843278; // 0x101020e
field public static final int updatePeriodMillis = 16843344; // 0x1010250
+ field public static final int urlBarResourceId = 16844164; // 0x1010584
field public static final int use32bitAbi = 16844053; // 0x1010515
field public static final int useDefaultMargins = 16843641; // 0x1010379
field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310
@@ -2215,34 +2216,34 @@ package android {
field public static final int Theme_DeviceDefault_Wallpaper = 16974140; // 0x103013c
field public static final int Theme_DeviceDefault_Wallpaper_NoTitleBar = 16974141; // 0x103013d
field public static final int Theme_Dialog = 16973835; // 0x103000b
- field public static final int Theme_Holo = 16973931; // 0x103006b
- field public static final int Theme_Holo_Dialog = 16973935; // 0x103006f
- field public static final int Theme_Holo_DialogWhenLarge = 16973943; // 0x1030077
- field public static final int Theme_Holo_DialogWhenLarge_NoActionBar = 16973944; // 0x1030078
- field public static final int Theme_Holo_Dialog_MinWidth = 16973936; // 0x1030070
- field public static final int Theme_Holo_Dialog_NoActionBar = 16973937; // 0x1030071
- field public static final int Theme_Holo_Dialog_NoActionBar_MinWidth = 16973938; // 0x1030072
- field public static final int Theme_Holo_InputMethod = 16973951; // 0x103007f
- field public static final int Theme_Holo_Light = 16973934; // 0x103006e
- field public static final int Theme_Holo_Light_DarkActionBar = 16974105; // 0x1030119
- field public static final int Theme_Holo_Light_Dialog = 16973939; // 0x1030073
- field public static final int Theme_Holo_Light_DialogWhenLarge = 16973945; // 0x1030079
- field public static final int Theme_Holo_Light_DialogWhenLarge_NoActionBar = 16973946; // 0x103007a
- field public static final int Theme_Holo_Light_Dialog_MinWidth = 16973940; // 0x1030074
- field public static final int Theme_Holo_Light_Dialog_NoActionBar = 16973941; // 0x1030075
- field public static final int Theme_Holo_Light_Dialog_NoActionBar_MinWidth = 16973942; // 0x1030076
- field public static final int Theme_Holo_Light_NoActionBar = 16974064; // 0x10300f0
- field public static final int Theme_Holo_Light_NoActionBar_Fullscreen = 16974065; // 0x10300f1
- field public static final int Theme_Holo_Light_NoActionBar_Overscan = 16974302; // 0x10301de
- field public static final int Theme_Holo_Light_NoActionBar_TranslucentDecor = 16974306; // 0x10301e2
- field public static final int Theme_Holo_Light_Panel = 16973948; // 0x103007c
- field public static final int Theme_Holo_NoActionBar = 16973932; // 0x103006c
- field public static final int Theme_Holo_NoActionBar_Fullscreen = 16973933; // 0x103006d
- field public static final int Theme_Holo_NoActionBar_Overscan = 16974301; // 0x10301dd
- field public static final int Theme_Holo_NoActionBar_TranslucentDecor = 16974305; // 0x10301e1
- field public static final int Theme_Holo_Panel = 16973947; // 0x103007b
- field public static final int Theme_Holo_Wallpaper = 16973949; // 0x103007d
- field public static final int Theme_Holo_Wallpaper_NoTitleBar = 16973950; // 0x103007e
+ field public static final deprecated int Theme_Holo = 16973931; // 0x103006b
+ field public static final deprecated int Theme_Holo_Dialog = 16973935; // 0x103006f
+ field public static final deprecated int Theme_Holo_DialogWhenLarge = 16973943; // 0x1030077
+ field public static final deprecated int Theme_Holo_DialogWhenLarge_NoActionBar = 16973944; // 0x1030078
+ field public static final deprecated int Theme_Holo_Dialog_MinWidth = 16973936; // 0x1030070
+ field public static final deprecated int Theme_Holo_Dialog_NoActionBar = 16973937; // 0x1030071
+ field public static final deprecated int Theme_Holo_Dialog_NoActionBar_MinWidth = 16973938; // 0x1030072
+ field public static final deprecated int Theme_Holo_InputMethod = 16973951; // 0x103007f
+ field public static final deprecated int Theme_Holo_Light = 16973934; // 0x103006e
+ field public static final deprecated int Theme_Holo_Light_DarkActionBar = 16974105; // 0x1030119
+ field public static final deprecated int Theme_Holo_Light_Dialog = 16973939; // 0x1030073
+ field public static final deprecated int Theme_Holo_Light_DialogWhenLarge = 16973945; // 0x1030079
+ field public static final deprecated int Theme_Holo_Light_DialogWhenLarge_NoActionBar = 16973946; // 0x103007a
+ field public static final deprecated int Theme_Holo_Light_Dialog_MinWidth = 16973940; // 0x1030074
+ field public static final deprecated int Theme_Holo_Light_Dialog_NoActionBar = 16973941; // 0x1030075
+ field public static final deprecated int Theme_Holo_Light_Dialog_NoActionBar_MinWidth = 16973942; // 0x1030076
+ field public static final deprecated int Theme_Holo_Light_NoActionBar = 16974064; // 0x10300f0
+ field public static final deprecated int Theme_Holo_Light_NoActionBar_Fullscreen = 16974065; // 0x10300f1
+ field public static final deprecated int Theme_Holo_Light_NoActionBar_Overscan = 16974302; // 0x10301de
+ field public static final deprecated int Theme_Holo_Light_NoActionBar_TranslucentDecor = 16974306; // 0x10301e2
+ field public static final deprecated int Theme_Holo_Light_Panel = 16973948; // 0x103007c
+ field public static final deprecated int Theme_Holo_NoActionBar = 16973932; // 0x103006c
+ field public static final deprecated int Theme_Holo_NoActionBar_Fullscreen = 16973933; // 0x103006d
+ field public static final deprecated int Theme_Holo_NoActionBar_Overscan = 16974301; // 0x10301dd
+ field public static final deprecated int Theme_Holo_NoActionBar_TranslucentDecor = 16974305; // 0x10301e1
+ field public static final deprecated int Theme_Holo_Panel = 16973947; // 0x103007b
+ field public static final deprecated int Theme_Holo_Wallpaper = 16973949; // 0x103007d
+ field public static final deprecated int Theme_Holo_Wallpaper_NoTitleBar = 16973950; // 0x103007e
field public static final int Theme_InputMethod = 16973908; // 0x1030054
field public static final int Theme_Light = 16973836; // 0x103000c
field public static final int Theme_Light_NoTitleBar = 16973837; // 0x103000d
@@ -3695,7 +3696,7 @@ package android.app {
method public boolean onCreateOptionsMenu(android.view.Menu);
method public boolean onCreatePanelMenu(int, android.view.Menu);
method public android.view.View onCreatePanelView(int);
- method public boolean onCreateThumbnail(android.graphics.Bitmap, android.graphics.Canvas);
+ method public deprecated boolean onCreateThumbnail(android.graphics.Bitmap, android.graphics.Canvas);
method public android.view.View onCreateView(java.lang.String, android.content.Context, android.util.AttributeSet);
method public android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
method protected void onDestroy();
@@ -6740,6 +6741,7 @@ package android.app.admin {
field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
field public static final int TAG_CERT_AUTHORITY_INSTALLED = 210029; // 0x3346d
field public static final int TAG_CERT_AUTHORITY_REMOVED = 210030; // 0x3346e
+ field public static final int TAG_CERT_VALIDATION_FAILURE = 210033; // 0x33471
field public static final int TAG_CRYPTO_SELF_TEST_COMPLETED = 210031; // 0x3346f
field public static final int TAG_KEYGUARD_DISABLED_FEATURES_SET = 210021; // 0x33465
field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
@@ -6748,6 +6750,7 @@ package android.app.admin {
field public static final int TAG_KEY_DESTRUCTION = 210026; // 0x3346a
field public static final int TAG_KEY_GENERATED = 210024; // 0x33468
field public static final int TAG_KEY_IMPORT = 210025; // 0x33469
+ field public static final int TAG_KEY_INTEGRITY_VIOLATION = 210032; // 0x33470
field public static final int TAG_LOGGING_STARTED = 210011; // 0x3345b
field public static final int TAG_LOGGING_STOPPED = 210012; // 0x3345c
field public static final int TAG_LOG_BUFFER_SIZE_CRITICAL = 210015; // 0x3345f
@@ -12552,6 +12555,7 @@ package android.database.sqlite {
method public abstract void onUpgrade(android.database.sqlite.SQLiteDatabase, int, int);
method public void setIdleConnectionTimeout(long);
method public void setLookasideConfig(int, int);
+ method public void setOpenParams(android.database.sqlite.SQLiteDatabase.OpenParams);
method public void setWriteAheadLoggingEnabled(boolean);
}
@@ -26752,7 +26756,7 @@ package android.net {
field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
field public static final java.lang.String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL";
field public static final java.lang.String ACTION_RESTRICT_BACKGROUND_CHANGED = "android.net.conn.RESTRICT_BACKGROUND_CHANGED";
- field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
+ field public static final deprecated java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
field public static final java.lang.String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL";
field public static final java.lang.String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
@@ -27028,6 +27032,7 @@ package android.net {
field public static final int NET_CAPABILITY_CBS = 5; // 0x5
field public static final int NET_CAPABILITY_DUN = 2; // 0x2
field public static final int NET_CAPABILITY_EIMS = 10; // 0xa
+ field public static final int NET_CAPABILITY_FOREGROUND = 19; // 0x13
field public static final int NET_CAPABILITY_FOTA = 3; // 0x3
field public static final int NET_CAPABILITY_IA = 7; // 0x7
field public static final int NET_CAPABILITY_IMS = 4; // 0x4
@@ -27036,6 +27041,7 @@ package android.net {
field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12
+ field public static final int NET_CAPABILITY_NOT_SUSPENDED = 21; // 0x15
field public static final int NET_CAPABILITY_NOT_VPN = 15; // 0xf
field public static final int NET_CAPABILITY_RCS = 8; // 0x8
field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
@@ -27992,23 +27998,23 @@ package android.net.wifi {
method public int updateNetwork(android.net.wifi.WifiConfiguration);
field public static final java.lang.String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
field public static final java.lang.String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
- field public static final int ERROR_AUTHENTICATING = 1; // 0x1
+ field public static final deprecated int ERROR_AUTHENTICATING = 1; // 0x1
field public static final deprecated java.lang.String EXTRA_BSSID = "bssid";
field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
field public static final java.lang.String EXTRA_NEW_RSSI = "newRssi";
- field public static final java.lang.String EXTRA_NEW_STATE = "newState";
+ field public static final deprecated java.lang.String EXTRA_NEW_STATE = "newState";
field public static final java.lang.String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
field public static final java.lang.String EXTRA_RESULTS_UPDATED = "resultsUpdated";
- field public static final java.lang.String EXTRA_SUPPLICANT_CONNECTED = "connected";
- field public static final java.lang.String EXTRA_SUPPLICANT_ERROR = "supplicantError";
+ field public static final deprecated java.lang.String EXTRA_SUPPLICANT_CONNECTED = "connected";
+ field public static final deprecated java.lang.String EXTRA_SUPPLICANT_ERROR = "supplicantError";
field public static final deprecated java.lang.String EXTRA_WIFI_INFO = "wifiInfo";
field public static final java.lang.String EXTRA_WIFI_STATE = "wifi_state";
field public static final java.lang.String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
field public static final java.lang.String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
field public static final java.lang.String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
field public static final java.lang.String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
- field public static final java.lang.String SUPPLICANT_CONNECTION_CHANGE_ACTION = "android.net.wifi.supplicant.CONNECTION_CHANGE";
- field public static final java.lang.String SUPPLICANT_STATE_CHANGED_ACTION = "android.net.wifi.supplicant.STATE_CHANGE";
+ field public static final deprecated java.lang.String SUPPLICANT_CONNECTION_CHANGE_ACTION = "android.net.wifi.supplicant.CONNECTION_CHANGE";
+ field public static final deprecated java.lang.String SUPPLICANT_STATE_CHANGED_ACTION = "android.net.wifi.supplicant.STATE_CHANGE";
field public static final int WIFI_MODE_FULL = 1; // 0x1
field public static final int WIFI_MODE_FULL_HIGH_PERF = 3; // 0x3
field public static final int WIFI_MODE_SCAN_ONLY = 2; // 0x2
@@ -28063,20 +28069,21 @@ package android.net.wifi {
method public abstract deprecated void onSucceeded();
}
- public class WpsInfo implements android.os.Parcelable {
- ctor public WpsInfo();
- ctor public WpsInfo(android.net.wifi.WpsInfo);
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field public java.lang.String BSSID;
- field public static final android.os.Parcelable.Creator<android.net.wifi.WpsInfo> CREATOR;
- field public static final int DISPLAY = 1; // 0x1
- field public static final int INVALID = 4; // 0x4
- field public static final int KEYPAD = 2; // 0x2
- field public static final int LABEL = 3; // 0x3
- field public static final int PBC = 0; // 0x0
- field public java.lang.String pin;
- field public int setup;
+ public deprecated class WpsInfo implements android.os.Parcelable {
+ ctor public deprecated WpsInfo();
+ ctor public deprecated WpsInfo(android.net.wifi.WpsInfo);
+ method public deprecated int describeContents();
+ method public deprecated java.lang.String toString();
+ method public deprecated void writeToParcel(android.os.Parcel, int);
+ field public deprecated java.lang.String BSSID;
+ field public static final deprecated android.os.Parcelable.Creator<android.net.wifi.WpsInfo> CREATOR;
+ field public static final deprecated int DISPLAY = 1; // 0x1
+ field public static final deprecated int INVALID = 4; // 0x4
+ field public static final deprecated int KEYPAD = 2; // 0x2
+ field public static final deprecated int LABEL = 3; // 0x3
+ field public static final deprecated int PBC = 0; // 0x0
+ field public deprecated java.lang.String pin;
+ field public deprecated int setup;
}
}
@@ -28530,6 +28537,7 @@ package android.net.wifi.rtt {
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.wifi.rtt.RangingResult> CREATOR;
field public static final int STATUS_FAIL = 1; // 0x1
+ field public static final int STATUS_RESPONDER_DOES_NOT_SUPPORT_IEEE80211MC = 2; // 0x2
field public static final int STATUS_SUCCESS = 0; // 0x0
}
@@ -33004,14 +33012,14 @@ package android.os {
}
public final class SystemClock {
+ method public static java.time.Clock currentNetworkTimeClock();
+ method public static long currentNetworkTimeMillis();
method public static long currentThreadTimeMillis();
method public static long elapsedRealtime();
- method public static java.time.Clock elapsedRealtimeClock();
method public static long elapsedRealtimeNanos();
method public static boolean setCurrentTimeMillis(long);
method public static void sleep(long);
method public static long uptimeMillis();
- method public static java.time.Clock uptimeMillisClock();
}
public class TestLooperManager {
@@ -36608,6 +36616,7 @@ package android.provider {
field public static final deprecated java.lang.String RADIO_NFC = "nfc";
field public static final deprecated java.lang.String RADIO_WIFI = "wifi";
field public static final java.lang.String RINGTONE = "ringtone";
+ field public static final java.lang.String RTT_CALLING_MODE = "rtt_calling_mode";
field public static final java.lang.String SCREEN_BRIGHTNESS = "screen_brightness";
field public static final java.lang.String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
field public static final int SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1; // 0x1
@@ -38417,6 +38426,7 @@ package android.security.keystore {
method public boolean isRandomizedEncryptionRequired();
method public boolean isStrongBoxBacked();
method public boolean isTrustedUserPresenceRequired();
+ method public boolean isUnlockedDeviceRequired();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationValidWhileOnBody();
method public boolean isUserConfirmationRequired();
@@ -38444,6 +38454,7 @@ package android.security.keystore {
method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setTrustedUserPresenceRequired(boolean);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
@@ -38535,6 +38546,8 @@ package android.security.keystore {
method public boolean isDigestsSpecified();
method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isRandomizedEncryptionRequired();
+ method public boolean isTrustedUserPresenceRequired();
+ method public boolean isUnlockedDeviceRequired();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationValidWhileOnBody();
method public boolean isUserConfirmationRequired();
@@ -38553,6 +38566,8 @@ package android.security.keystore {
method public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date);
method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
+ method public android.security.keystore.KeyProtection.Builder setTrustedUserPresenceRequired(boolean);
+ method public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int);
@@ -38655,14 +38670,14 @@ package android.service.autofill {
}
public final class DateTransformation implements android.os.Parcelable android.service.autofill.Transformation {
- ctor public DateTransformation(android.view.autofill.AutofillId, java.text.DateFormat);
+ ctor public DateTransformation(android.view.autofill.AutofillId, android.icu.text.DateFormat);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.autofill.DateTransformation> CREATOR;
}
public final class DateValueSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer {
- ctor public DateValueSanitizer(java.text.DateFormat);
+ ctor public DateValueSanitizer(android.icu.text.DateFormat);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.autofill.DateValueSanitizer> CREATOR;
@@ -38673,7 +38688,7 @@ package android.service.autofill {
}
public static final class FieldClassification.Match {
- method public java.lang.String getRemoteId();
+ method public java.lang.String getCategoryId();
method public float getScore();
}
@@ -38838,6 +38853,7 @@ package android.service.autofill {
method public int describeContents();
method public java.lang.String getFieldClassificationAlgorithm();
method public java.lang.String getId();
+ method public static int getMaxCategoryCount();
method public static int getMaxFieldClassificationIdsSize();
method public static int getMaxUserDataSize();
method public static int getMaxValueLength();
@@ -40612,6 +40628,7 @@ package android.telecom {
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
+ field public static final int PROPERTY_RTT = 1024; // 0x400
field public static final int PROPERTY_SELF_MANAGED = 256; // 0x100
field public static final int PROPERTY_WIFI = 8; // 0x8
}
@@ -40705,8 +40722,8 @@ package android.telecom {
method public final void setActive();
method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
method public final void setConnectionCapabilities(int);
- method public final void setConnectionElapsedTime(long);
method public final void setConnectionProperties(int);
+ method public final void setConnectionStartElapsedRealTime(long);
method public final void setConnectionTime(long);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
@@ -44454,10 +44471,12 @@ package android.text.style {
public class TypefaceSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
ctor public TypefaceSpan(java.lang.String);
+ ctor public TypefaceSpan(android.graphics.Typeface);
ctor public TypefaceSpan(android.os.Parcel);
method public int describeContents();
method public java.lang.String getFamily();
method public int getSpanTypeId();
+ method public android.graphics.Typeface getTypeface();
method public void updateDrawState(android.text.TextPaint);
method public void updateMeasureState(android.text.TextPaint);
method public void writeToParcel(android.os.Parcel, int);
@@ -49762,6 +49781,8 @@ package android.view.autofill {
method public boolean isFieldClassificationEnabled();
method public void notifyValueChanged(android.view.View);
method public void notifyValueChanged(android.view.View, int, android.view.autofill.AutofillValue);
+ method public void notifyViewClicked(android.view.View);
+ method public void notifyViewClicked(android.view.View, int);
method public void notifyViewEntered(android.view.View);
method public void notifyViewEntered(android.view.View, int, android.graphics.Rect);
method public void notifyViewExited(android.view.View);
@@ -50269,6 +50290,7 @@ package android.view.textclassifier {
method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence);
method public default java.util.Collection<java.lang.String> getEntitiesForPreset(int);
method public default android.view.textclassifier.logging.Logger getLogger(android.view.textclassifier.logging.Logger.Config);
+ method public default int getMaxGenerateLinksTextLength();
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
@@ -50723,41 +50745,37 @@ package android.webkit {
}
public class TracingConfig {
- ctor public TracingConfig(int);
- ctor public TracingConfig(int, java.lang.String, int);
- method public java.lang.String getCustomCategoryPattern();
- method public int getPresetCategories();
+ method public java.util.List<java.lang.String> getCustomIncludedCategories();
+ method public int getPredefinedCategories();
method public int getTracingMode();
- field public static final int CATEGORIES_FRAME_VIEWER = 4; // 0x4
- field public static final int CATEGORIES_INPUT_LATENCY = 1; // 0x1
- field public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 3; // 0x3
- field public static final int CATEGORIES_NONE = -1; // 0xffffffff
- field public static final int CATEGORIES_RENDERING = 2; // 0x2
- field public static final int CATEGORIES_WEB_DEVELOPER = 0; // 0x0
+ field public static final int CATEGORIES_ALL = 1; // 0x1
+ field public static final int CATEGORIES_ANDROID_WEBVIEW = 2; // 0x2
+ field public static final int CATEGORIES_FRAME_VIEWER = 64; // 0x40
+ field public static final int CATEGORIES_INPUT_LATENCY = 8; // 0x8
+ field public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 32; // 0x20
+ field public static final int CATEGORIES_NONE = 0; // 0x0
+ field public static final int CATEGORIES_RENDERING = 16; // 0x10
+ field public static final int CATEGORIES_WEB_DEVELOPER = 4; // 0x4
field public static final int RECORD_CONTINUOUSLY = 1; // 0x1
- field public static final int RECORD_TO_CONSOLE = 3; // 0x3
field public static final int RECORD_UNTIL_FULL = 0; // 0x0
field public static final int RECORD_UNTIL_FULL_LARGE_BUFFER = 2; // 0x2
}
+ public static class TracingConfig.Builder {
+ ctor public TracingConfig.Builder();
+ method public android.webkit.TracingConfig.Builder addCategories(int...);
+ method public android.webkit.TracingConfig.Builder addCategories(java.lang.String...);
+ method public android.webkit.TracingConfig.Builder addCategories(java.util.Collection<java.lang.String>);
+ method public android.webkit.TracingConfig build();
+ method public android.webkit.TracingConfig.Builder setTracingMode(int);
+ }
+
public abstract class TracingController {
ctor public TracingController();
method public static android.webkit.TracingController getInstance();
method public abstract boolean isTracing();
- method public abstract boolean start(android.webkit.TracingConfig);
- method public abstract boolean stop();
- method public abstract boolean stopAndFlush(android.webkit.TracingController.TracingOutputStream, android.os.Handler);
- }
-
- public static abstract interface TracingController.TracingOutputStream {
- method public abstract void complete();
- method public abstract void write(byte[]);
- }
-
- public class TracingFileOutputStream implements android.webkit.TracingController.TracingOutputStream {
- ctor public TracingFileOutputStream(java.lang.String) throws java.io.FileNotFoundException;
- method public void complete();
- method public void write(byte[]);
+ method public abstract void start(android.webkit.TracingConfig);
+ method public abstract boolean stop(java.io.OutputStream, java.util.concurrent.Executor);
}
public final class URLUtil {
diff --git a/api/removed.txt b/api/removed.txt
index 2aab223ed281..55022f36a016 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -257,6 +257,12 @@ package android.os {
ctor public RecoverySystem();
}
+ public final class SystemClock {
+ method public static java.time.Clock elapsedRealtimeClock();
+ method public static java.time.Clock uptimeClock();
+ method public static deprecated java.time.Clock uptimeMillisClock();
+ }
+
public class TestLooperManager {
method public deprecated android.os.MessageQueue getQueue();
}
diff --git a/api/system-current.txt b/api/system-current.txt
index adc050017917..affaf0de2094 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -229,7 +229,6 @@ package android.app {
method public boolean convertToTranslucent(android.app.Activity.TranslucentConversionListener, android.app.ActivityOptions);
method public deprecated boolean isBackgroundVisibleBehind();
method public deprecated void onBackgroundVisibleBehindChanged(boolean);
- method public void setDisablePreviewScreenshots(boolean);
}
public static abstract interface Activity.TranslucentConversionListener {
@@ -343,11 +342,13 @@ package android.app {
method public java.lang.String getChannelId();
method public android.app.PendingIntent getContentIntent();
method public android.app.PendingIntent getDeleteIntent();
+ method public boolean getSuppressShowOverApps();
method public boolean isAvailableOnTv();
method public android.app.Notification.TvExtender setChannel(java.lang.String);
method public android.app.Notification.TvExtender setChannelId(java.lang.String);
method public android.app.Notification.TvExtender setContentIntent(android.app.PendingIntent);
method public android.app.Notification.TvExtender setDeleteIntent(android.app.PendingIntent);
+ method public android.app.Notification.TvExtender setSuppressShowOverApps(boolean);
}
public final class NotificationChannel implements android.os.Parcelable {
@@ -435,6 +436,19 @@ package android.app.admin {
field public static final int STATE_USER_UNMANAGED = 0; // 0x0
}
+ public class SystemUpdatePolicy implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.app.admin.SystemUpdatePolicy.InstallationOption getInstallationOptionAt(long);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.admin.SystemUpdatePolicy> CREATOR;
+ field public static final int TYPE_PAUSE = 4; // 0x4
+ }
+
+ public static class SystemUpdatePolicy.InstallationOption {
+ method public long getEffectiveTime();
+ method public int getType();
+ }
+
}
package android.app.backup {
@@ -2522,12 +2536,15 @@ package android.media {
public class AudioManager {
method public deprecated int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes);
+ method public void clearAudioServerStateCallback();
method public int dispatchAudioFocusChange(android.media.AudioFocusInfo, int, android.media.audiopolicy.AudioPolicy);
+ method public boolean isAudioServerRunning();
method public boolean isHdmiSystemAudioSupported();
method public int registerAudioPolicy(android.media.audiopolicy.AudioPolicy);
method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException;
method public deprecated int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException;
method public int requestAudioFocus(android.media.AudioFocusRequest, android.media.audiopolicy.AudioPolicy);
+ method public void setAudioServerStateCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioServerStateCallback);
method public void setFocusRequestResult(android.media.AudioFocusInfo, int, android.media.audiopolicy.AudioPolicy);
method public void unregisterAudioPolicyAsync(android.media.audiopolicy.AudioPolicy);
field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1
@@ -2535,6 +2552,12 @@ package android.media {
field public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 2; // 0x2
}
+ public static abstract class AudioManager.AudioServerStateCallback {
+ ctor public AudioManager.AudioServerStateCallback();
+ method public void onAudioServerDown();
+ method public void onAudioServerUp();
+ }
+
public final class AudioPlaybackConfiguration implements android.os.Parcelable {
method public int getClientPid();
method public int getClientUid();
@@ -3587,11 +3610,14 @@ package android.os {
}
public abstract class HwBinder implements android.os.IHwBinder {
+ ctor public HwBinder();
method public static final void configureRpcThreadpool(long, boolean);
method public static void enableInstrumentation();
method public static final android.os.IHwBinder getService(java.lang.String, java.lang.String) throws java.util.NoSuchElementException, android.os.RemoteException;
method public static final android.os.IHwBinder getService(java.lang.String, java.lang.String, boolean) throws java.util.NoSuchElementException, android.os.RemoteException;
method public static final void joinRpcThreadpool();
+ method public abstract void onTransact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
+ method public final void registerService(java.lang.String) throws android.os.RemoteException;
method public final void transact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
}
@@ -4143,6 +4169,8 @@ package android.provider {
method public static void resetToDefaults(android.content.ContentResolver, java.lang.String);
field public static final java.lang.String AUTOFILL_COMPAT_ALLOWED_PACKAGES = "autofill_compat_allowed_packages";
field public static final java.lang.String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus";
+ field public static final java.lang.String INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT = "install_carrier_app_notification_persistent";
+ field public static final java.lang.String INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS = "install_carrier_app_notification_sleep_millis";
field public static final java.lang.String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update";
field public static final java.lang.String THEATER_MODE_ON = "theater_mode_on";
field public static final java.lang.String WEBVIEW_MULTIPROCESS = "webview_multiprocess";
@@ -4154,6 +4182,7 @@ package android.provider {
method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String, java.lang.String, boolean);
method public static void resetToDefaults(android.content.ContentResolver, java.lang.String);
field public static final java.lang.String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = "autofill_field_classification";
+ field public static final java.lang.String AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT = "autofill_user_data_max_category_count";
field public static final java.lang.String AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE = "autofill_user_data_max_field_classification_size";
field public static final java.lang.String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = "autofill_user_data_max_user_data_size";
field public static final java.lang.String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length";
diff --git a/api/test-current.txt b/api/test-current.txt
index b02da04bbcd1..2e47e003a72c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -541,6 +541,7 @@ package android.provider {
field public static final java.lang.String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED = "accessibility_display_magnification_enabled";
field public static final java.lang.String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = "autofill_field_classification";
field public static final java.lang.String AUTOFILL_SERVICE = "autofill_service";
+ field public static final java.lang.String AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT = "autofill_user_data_max_category_count";
field public static final java.lang.String AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE = "autofill_user_data_max_field_classification_size";
field public static final java.lang.String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = "autofill_user_data_max_user_data_size";
field public static final java.lang.String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length";
@@ -1047,10 +1048,20 @@ package android.view.accessibility {
}
+package android.view.animation {
+
+ public class AnimationUtils {
+ method public static void lockAnimationClock(long);
+ method public static void unlockAnimationClock();
+ }
+
+}
+
package android.view.autofill {
public final class AutofillId implements android.os.Parcelable {
ctor public AutofillId(int);
+ ctor public AutofillId(android.view.autofill.AutofillId, int);
}
}
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 813335a688ab..c04e61b77274 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -172,6 +172,8 @@ public class Am extends BaseCommand {
} else if (opt.equals("--no_window_animation")
|| opt.equals("--no-window-animation")) {
instrument.noWindowAnimation = true;
+ } else if (opt.equals("--no-hidden-api-checks")) {
+ instrument.disableHiddenApiChecks = true;
} else if (opt.equals("--user")) {
instrument.userId = parseUserArg(nextArgRequired());
} else if (opt.equals("--abi")) {
diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java
index d79b1a61eb5b..0dade0b2ba81 100644
--- a/cmds/am/src/com/android/commands/am/Instrument.java
+++ b/cmds/am/src/com/android/commands/am/Instrument.java
@@ -73,12 +73,17 @@ public class Instrument {
boolean protoFile = false; // write proto to a file
String logPath = null;
public boolean noWindowAnimation = false;
+ public boolean disableHiddenApiChecks = false;
public String abi = null;
public int userId = UserHandle.USER_CURRENT;
public Bundle args = new Bundle();
// Required
public String componentNameArg;
+ // Disable hidden API checks for the newly started instrumentation.
+ // Must be kept in sync with ActivityManagerService.
+ private static final int INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS = 1 << 0;
+
/**
* Construct the instrument command runner.
*/
@@ -475,7 +480,8 @@ public class Instrument {
}
// Start the instrumentation
- if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId,
+ int flags = disableHiddenApiChecks ? INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS : 0;
+ if (!mAm.startInstrumentation(cn, profileFile, flags, args, watcher, connection, userId,
abi)) {
throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
}
diff --git a/cmds/incident_helper/OWNERS b/cmds/incident_helper/OWNERS
new file mode 100644
index 000000000000..1a68a32c4308
--- /dev/null
+++ b/cmds/incident_helper/OWNERS
@@ -0,0 +1,2 @@
+jinyithu@google.com
+kwekua@google.com
diff --git a/cmds/incident_helper/src/parsers/CpuFreqParser.cpp b/cmds/incident_helper/src/parsers/CpuFreqParser.cpp
index 02f1ce7cc0fc..fde17bd97a7f 100644
--- a/cmds/incident_helper/src/parsers/CpuFreqParser.cpp
+++ b/cmds/incident_helper/src/parsers/CpuFreqParser.cpp
@@ -62,15 +62,15 @@ CpuFreqParser::Parse(const int in, const int out) const
ProtoOutputStream proto;
long jiffyHz = sysconf(_SC_CLK_TCK);
- proto.write(CpuFreq::JIFFY_HZ, (int)jiffyHz);
+ proto.write(CpuFreqProto::JIFFY_HZ, (int)jiffyHz);
for (int i=0; i<numCpus; i++) {
- long long token = proto.start(CpuFreq::CPU_FREQS);
- proto.write(CpuFreqStats::CPU_NAME, header[i+1]);
+ long long token = proto.start(CpuFreqProto::CPU_FREQS);
+ proto.write(CpuFreqProto::Stats::CPU_NAME, header[i+1]);
for (vector<pair<int, long long>>::iterator it = cpucores[i].begin(); it != cpucores[i].end(); it++) {
- long long stateToken = proto.start(CpuFreqStats::TIMES);
- proto.write(CpuFreqStats::TimeInState::STATE_KHZ, it->first);
- proto.write(CpuFreqStats::TimeInState::TIME_JIFFY, it->second);
+ long long stateToken = proto.start(CpuFreqProto::Stats::TIMES);
+ proto.write(CpuFreqProto::Stats::TimeInState::STATE_KHZ, it->first);
+ proto.write(CpuFreqProto::Stats::TimeInState::TIME_JIFFY, it->second);
proto.end(stateToken);
}
proto.end(token);
diff --git a/cmds/incident_helper/src/parsers/CpuInfoParser.cpp b/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
index d73de54d8c5d..b2b431c62866 100644
--- a/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
+++ b/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
@@ -54,11 +54,11 @@ CpuInfoParser::Parse(const int in, const int out) const
bool nextToUsage = false;
ProtoOutputStream proto;
- Table table(CpuInfo::Task::_FIELD_NAMES, CpuInfo::Task::_FIELD_IDS, CpuInfo::Task::_FIELD_COUNT);
- table.addEnumTypeMap("s", CpuInfo::Task::_ENUM_STATUS_NAMES,
- CpuInfo::Task::_ENUM_STATUS_VALUES, CpuInfo::Task::_ENUM_STATUS_COUNT);
- table.addEnumTypeMap("pcy", CpuInfo::Task::_ENUM_POLICY_NAMES,
- CpuInfo::Task::_ENUM_POLICY_VALUES, CpuInfo::Task::_ENUM_POLICY_COUNT);
+ Table table(CpuInfoProto::Task::_FIELD_NAMES, CpuInfoProto::Task::_FIELD_IDS, CpuInfoProto::Task::_FIELD_COUNT);
+ table.addEnumTypeMap("s", CpuInfoProto::Task::_ENUM_STATUS_NAMES,
+ CpuInfoProto::Task::_ENUM_STATUS_VALUES, CpuInfoProto::Task::_ENUM_STATUS_COUNT);
+ table.addEnumTypeMap("pcy", CpuInfoProto::Task::_ENUM_POLICY_NAMES,
+ CpuInfoProto::Task::_ENUM_POLICY_VALUES, CpuInfoProto::Task::_ENUM_POLICY_COUNT);
// parse line by line
while (reader.readLine(&line)) {
@@ -67,33 +67,33 @@ CpuInfoParser::Parse(const int in, const int out) const
nline++;
if (stripPrefix(&line, "Tasks:")) {
- writeSuffixLine(&proto, CpuInfo::TASK_STATS, line, COMMA_DELIMITER,
- CpuInfo::TaskStats::_FIELD_COUNT,
- CpuInfo::TaskStats::_FIELD_NAMES,
- CpuInfo::TaskStats::_FIELD_IDS);
+ writeSuffixLine(&proto, CpuInfoProto::TASK_STATS, line, COMMA_DELIMITER,
+ CpuInfoProto::TaskStats::_FIELD_COUNT,
+ CpuInfoProto::TaskStats::_FIELD_NAMES,
+ CpuInfoProto::TaskStats::_FIELD_IDS);
continue;
}
if (stripPrefix(&line, "Mem:")) {
- writeSuffixLine(&proto, CpuInfo::MEM, line, COMMA_DELIMITER,
- CpuInfo::MemStats::_FIELD_COUNT,
- CpuInfo::MemStats::_FIELD_NAMES,
- CpuInfo::MemStats::_FIELD_IDS);
+ writeSuffixLine(&proto, CpuInfoProto::MEM, line, COMMA_DELIMITER,
+ CpuInfoProto::MemStats::_FIELD_COUNT,
+ CpuInfoProto::MemStats::_FIELD_NAMES,
+ CpuInfoProto::MemStats::_FIELD_IDS);
continue;
}
if (stripPrefix(&line, "Swap:")) {
- writeSuffixLine(&proto, CpuInfo::SWAP, line, COMMA_DELIMITER,
- CpuInfo::MemStats::_FIELD_COUNT,
- CpuInfo::MemStats::_FIELD_NAMES,
- CpuInfo::MemStats::_FIELD_IDS);
+ writeSuffixLine(&proto, CpuInfoProto::SWAP, line, COMMA_DELIMITER,
+ CpuInfoProto::MemStats::_FIELD_COUNT,
+ CpuInfoProto::MemStats::_FIELD_NAMES,
+ CpuInfoProto::MemStats::_FIELD_IDS);
nextToSwap = true;
continue;
}
if (nextToSwap) {
- writeSuffixLine(&proto, CpuInfo::CPU_USAGE, line, DEFAULT_WHITESPACE,
- CpuInfo::CpuUsage::_FIELD_COUNT,
- CpuInfo::CpuUsage::_FIELD_NAMES,
- CpuInfo::CpuUsage::_FIELD_IDS);
+ writeSuffixLine(&proto, CpuInfoProto::CPU_USAGE, line, DEFAULT_WHITESPACE,
+ CpuInfoProto::CpuUsage::_FIELD_COUNT,
+ CpuInfoProto::CpuUsage::_FIELD_NAMES,
+ CpuInfoProto::CpuUsage::_FIELD_IDS);
nextToUsage = true;
nextToSwap = false;
continue;
@@ -138,7 +138,7 @@ CpuInfoParser::Parse(const int in, const int out) const
continue;
}
- long long token = proto.start(CpuInfo::TASKS);
+ long long token = proto.start(CpuInfoProto::TASKS);
for (int i=0; i<(int)record.size(); i++) {
if (!table.insertField(&proto, header[i], record[i])) {
fprintf(stderr, "[%s]Line %d fails to insert field %s with value %s\n",
diff --git a/cmds/incident_helper/src/parsers/KernelWakesParser.cpp b/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
index cae51abbe57f..28816ea75a75 100644
--- a/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
+++ b/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
@@ -33,7 +33,9 @@ KernelWakesParser::Parse(const int in, const int out) const
int nline = 0;
ProtoOutputStream proto;
- Table table(WakeupSourceProto::_FIELD_NAMES, WakeupSourceProto::_FIELD_IDS, WakeupSourceProto::_FIELD_COUNT);
+ Table table(KernelWakeSourcesProto::WakeupSource::_FIELD_NAMES,
+ KernelWakeSourcesProto::WakeupSource::_FIELD_IDS,
+ KernelWakeSourcesProto::WakeupSource::_FIELD_COUNT);
// parse line by line
while (reader.readLine(&line)) {
@@ -57,7 +59,7 @@ KernelWakesParser::Parse(const int in, const int out) const
continue;
}
- long long token = proto.start(KernelWakeSources::WAKEUP_SOURCES);
+ long long token = proto.start(KernelWakeSourcesProto::WAKEUP_SOURCES);
for (int i=0; i<(int)record.size(); i++) {
if (!table.insertField(&proto, header[i], record[i])) {
fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
diff --git a/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp b/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp
index f1b93ff9ec41..45a0e7b459d2 100644
--- a/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp
+++ b/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp
@@ -33,7 +33,9 @@ PageTypeInfoParser::Parse(const int in, const int out) const
header_t blockHeader;
ProtoOutputStream proto;
- Table table(BlockProto::_FIELD_NAMES, BlockProto::_FIELD_IDS, BlockProto::_FIELD_COUNT);
+ Table table(PageTypeInfoProto::Block::_FIELD_NAMES,
+ PageTypeInfoProto::Block::_FIELD_IDS,
+ PageTypeInfoProto::Block::_FIELD_COUNT);
while (reader.readLine(&line)) {
if (line.empty()) {
@@ -44,11 +46,11 @@ PageTypeInfoParser::Parse(const int in, const int out) const
if (stripPrefix(&line, "Page block order:")) {
pageBlockOrder = toInt(line);
- proto.write(PageTypeInfo::PAGE_BLOCK_ORDER, pageBlockOrder);
+ proto.write(PageTypeInfoProto::PAGE_BLOCK_ORDER, pageBlockOrder);
continue;
}
if (stripPrefix(&line, "Pages per block:")) {
- proto.write(PageTypeInfo::PAGES_PER_BLOCK, toInt(line));
+ proto.write(PageTypeInfoProto::PAGES_PER_BLOCK, toInt(line));
continue;
}
if (stripPrefix(&line, "Free pages count per migrate type at order")) {
@@ -62,14 +64,14 @@ PageTypeInfoParser::Parse(const int in, const int out) const
record_t record = parseRecord(line, COMMA_DELIMITER);
if (migrateTypeSession && record.size() == 3) {
- long long token = proto.start(PageTypeInfo::MIGRATE_TYPES);
+ long long token = proto.start(PageTypeInfoProto::MIGRATE_TYPES);
// expect part 0 starts with "Node"
if (stripPrefix(&record[0], "Node")) {
- proto.write(MigrateTypeProto::NODE, toInt(record[0]));
+ proto.write(PageTypeInfoProto::MigrateType::NODE, toInt(record[0]));
} else return BAD_VALUE;
// expect part 1 starts with "zone"
if (stripPrefix(&record[1], "zone")) {
- proto.write(MigrateTypeProto::ZONE, record[1]);
+ proto.write(PageTypeInfoProto::MigrateType::ZONE, record[1]);
} else return BAD_VALUE;
// expect part 2 starts with "type"
if (stripPrefix(&record[2], "type")) {
@@ -83,22 +85,22 @@ PageTypeInfoParser::Parse(const int in, const int out) const
int pageCountsSize = pageBlockOrder + 2;
if ((int)pageCounts.size() != pageCountsSize) return BAD_VALUE;
- proto.write(MigrateTypeProto::TYPE, pageCounts[0]);
+ proto.write(PageTypeInfoProto::MigrateType::TYPE, pageCounts[0]);
for (auto i=1; i<pageCountsSize; i++) {
- proto.write(MigrateTypeProto::FREE_PAGES_COUNT, toInt(pageCounts[i]));
+ proto.write(PageTypeInfoProto::MigrateType::FREE_PAGES_COUNT, toInt(pageCounts[i]));
}
} else return BAD_VALUE;
proto.end(token);
} else if (!blockHeader.empty() && record.size() == 2) {
- long long token = proto.start(PageTypeInfo::BLOCKS);
+ long long token = proto.start(PageTypeInfoProto::BLOCKS);
if (stripPrefix(&record[0], "Node")) {
- proto.write(BlockProto::NODE, toInt(record[0]));
+ proto.write(PageTypeInfoProto::Block::NODE, toInt(record[0]));
} else return BAD_VALUE;
if (stripPrefix(&record[1], "zone")) {
record_t blockCounts = parseRecord(record[1]);
- proto.write(BlockProto::ZONE, blockCounts[0]);
+ proto.write(PageTypeInfoProto::Block::ZONE, blockCounts[0]);
for (size_t i=0; i<blockHeader.size(); i++) {
if (!table.insertField(&proto, blockHeader[i], blockCounts[i+1])) {
diff --git a/cmds/incident_helper/src/parsers/ProcrankParser.cpp b/cmds/incident_helper/src/parsers/ProcrankParser.cpp
index a4eb0fdfd988..c1c458e69ddf 100644
--- a/cmds/incident_helper/src/parsers/ProcrankParser.cpp
+++ b/cmds/incident_helper/src/parsers/ProcrankParser.cpp
@@ -33,7 +33,7 @@ ProcrankParser::Parse(const int in, const int out) const
int nline = 0;
ProtoOutputStream proto;
- Table table(ProcessProto::_FIELD_NAMES, ProcessProto::_FIELD_IDS, ProcessProto::_FIELD_COUNT);
+ Table table(ProcrankProto::Process::_FIELD_NAMES, ProcrankProto::Process::_FIELD_IDS, ProcrankProto::Process::_FIELD_COUNT);
string zram, ram, total;
// parse line by line
@@ -66,7 +66,7 @@ ProcrankParser::Parse(const int in, const int out) const
continue;
}
- long long token = proto.start(Procrank::PROCESSES);
+ long long token = proto.start(ProcrankProto::PROCESSES);
for (int i=0; i<(int)record.size(); i++) {
if (!table.insertField(&proto, header[i], record[i])) {
fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
@@ -77,23 +77,23 @@ ProcrankParser::Parse(const int in, const int out) const
}
// add summary
- long long token = proto.start(Procrank::SUMMARY);
+ long long token = proto.start(ProcrankProto::SUMMARY);
if (!total.empty()) {
record = parseRecord(total);
- long long token = proto.start(SummaryProto::TOTAL);
+ long long token = proto.start(ProcrankProto::Summary::TOTAL);
for (int i=(int)record.size(); i>0; i--) {
table.insertField(&proto, header[header.size() - i].c_str(), record[record.size() - i].c_str());
}
proto.end(token);
}
if (!zram.empty()) {
- long long token = proto.start(SummaryProto::ZRAM);
- proto.write(ZramProto::RAW_TEXT, zram);
+ long long token = proto.start(ProcrankProto::Summary::ZRAM);
+ proto.write(ProcrankProto::Summary::Zram::RAW_TEXT, zram);
proto.end(token);
}
if (!ram.empty()) {
- long long token = proto.start(SummaryProto::RAM);
- proto.write(RamProto::RAW_TEXT, ram);
+ long long token = proto.start(ProcrankProto::Summary::RAM);
+ proto.write(ProcrankProto::Summary::Ram::RAW_TEXT, ram);
proto.end(token);
}
proto.end(token);
diff --git a/cmds/incident_helper/src/parsers/PsParser.cpp b/cmds/incident_helper/src/parsers/PsParser.cpp
index e9014cacfa0b..420775fb5f04 100644
--- a/cmds/incident_helper/src/parsers/PsParser.cpp
+++ b/cmds/incident_helper/src/parsers/PsParser.cpp
@@ -33,12 +33,12 @@ status_t PsParser::Parse(const int in, const int out) const {
int diff = 0;
ProtoOutputStream proto;
- Table table(PsDumpProto::Process::_FIELD_NAMES, PsDumpProto::Process::_FIELD_IDS, PsDumpProto::Process::_FIELD_COUNT);
+ Table table(PsProto::Process::_FIELD_NAMES, PsProto::Process::_FIELD_IDS, PsProto::Process::_FIELD_COUNT);
const char* pcyNames[] = { "fg", "bg", "ta" };
- const int pcyValues[] = {PsDumpProto::Process::POLICY_FG, PsDumpProto::Process::POLICY_BG, PsDumpProto::Process::POLICY_TA};
+ const int pcyValues[] = {PsProto::Process::POLICY_FG, PsProto::Process::POLICY_BG, PsProto::Process::POLICY_TA};
table.addEnumTypeMap("pcy", pcyNames, pcyValues, 3);
const char* sNames[] = { "D", "R", "S", "T", "t", "X", "Z" };
- const int sValues[] = {PsDumpProto::Process::STATE_D, PsDumpProto::Process::STATE_R, PsDumpProto::Process::STATE_S, PsDumpProto::Process::STATE_T, PsDumpProto::Process::STATE_TRACING, PsDumpProto::Process::STATE_X, PsDumpProto::Process::STATE_Z};
+ const int sValues[] = {PsProto::Process::STATE_D, PsProto::Process::STATE_R, PsProto::Process::STATE_S, PsProto::Process::STATE_T, PsProto::Process::STATE_TRACING, PsProto::Process::STATE_X, PsProto::Process::STATE_Z};
table.addEnumTypeMap("s", sNames, sValues, 7);
// Parse line by line
@@ -71,7 +71,7 @@ status_t PsParser::Parse(const int in, const int out) const {
continue;
}
- long long token = proto.start(PsDumpProto::PROCESSES);
+ long long token = proto.start(PsProto::PROCESSES);
for (int i=0; i<(int)record.size(); i++) {
if (!table.insertField(&proto, header[i], record[i])) {
fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
diff --git a/cmds/incident_helper/tests/CpuFreqParser_test.cpp b/cmds/incident_helper/tests/CpuFreqParser_test.cpp
index 82deee42687f..0839a7e45edd 100644
--- a/cmds/incident_helper/tests/CpuFreqParser_test.cpp
+++ b/cmds/incident_helper/tests/CpuFreqParser_test.cpp
@@ -52,14 +52,14 @@ protected:
TEST_F(CpuFreqParserTest, Success) {
const string testFile = kTestDataPath + "cpufreq.txt";
CpuFreqParser parser;
- CpuFreq expected;
+ CpuFreqProto expected;
long jiffyHz = sysconf(_SC_CLK_TCK);
expected.set_jiffy_hz(jiffyHz);
- CpuFreqStats::TimeInState* state;
+ CpuFreqProto::Stats::TimeInState* state;
- CpuFreqStats* cpu0 = expected.add_cpu_freqs();
+ CpuFreqProto::Stats* cpu0 = expected.add_cpu_freqs();
cpu0->set_cpu_name("cpu0");
state = cpu0->add_times();
state->set_state_khz(307200);
@@ -71,7 +71,7 @@ TEST_F(CpuFreqParserTest, Success) {
state->set_state_khz(768000);
state->set_time_jiffy(22652);
- CpuFreqStats* cpu1 = expected.add_cpu_freqs();
+ CpuFreqProto::Stats* cpu1 = expected.add_cpu_freqs();
cpu1->set_cpu_name("cpu1");
state = cpu1->add_times();
state->set_state_khz(307200);
@@ -83,7 +83,7 @@ TEST_F(CpuFreqParserTest, Success) {
state->set_state_khz(768000);
state->set_time_jiffy(22652);
- CpuFreqStats* cpu2 = expected.add_cpu_freqs();
+ CpuFreqProto::Stats* cpu2 = expected.add_cpu_freqs();
cpu2->set_cpu_name("cpu2");
state = cpu2->add_times();
state->set_state_khz(307200);
@@ -98,7 +98,7 @@ TEST_F(CpuFreqParserTest, Success) {
state->set_state_khz(825600);
state->set_time_jiffy(13173);
- CpuFreqStats* cpu3 = expected.add_cpu_freqs();
+ CpuFreqProto::Stats* cpu3 = expected.add_cpu_freqs();
cpu3->set_cpu_name("cpu3");
state = cpu3->add_times();
state->set_state_khz(307200);
diff --git a/cmds/incident_helper/tests/CpuInfoParser_test.cpp b/cmds/incident_helper/tests/CpuInfoParser_test.cpp
index 8dce53e46492..2e50d631715e 100644
--- a/cmds/incident_helper/tests/CpuInfoParser_test.cpp
+++ b/cmds/incident_helper/tests/CpuInfoParser_test.cpp
@@ -52,28 +52,28 @@ protected:
TEST_F(CpuInfoParserTest, Success) {
const string testFile = kTestDataPath + "cpuinfo.txt";
CpuInfoParser parser;
- CpuInfo expected;
+ CpuInfoProto expected;
- CpuInfo::TaskStats* taskStats = expected.mutable_task_stats();
+ CpuInfoProto::TaskStats* taskStats = expected.mutable_task_stats();
taskStats->set_total(2038);
taskStats->set_running(1);
taskStats->set_sleeping(2033);
taskStats->set_stopped(0);
taskStats->set_zombie(0);
- CpuInfo::MemStats* mem = expected.mutable_mem();
+ CpuInfoProto::MemStats* mem = expected.mutable_mem();
mem->set_total(3842668);
mem->set_used(3761936);
mem->set_free(80732);
mem->set_buffers(220188);
- CpuInfo::MemStats* swap = expected.mutable_swap();
+ CpuInfoProto::MemStats* swap = expected.mutable_swap();
swap->set_total(524284);
swap->set_used(25892);
swap->set_free(498392);
swap->set_cached(1316952);
- CpuInfo::CpuUsage* usage = expected.mutable_cpu_usage();
+ CpuInfoProto::CpuUsage* usage = expected.mutable_cpu_usage();
usage->set_cpu(400);
usage->set_user(17);
usage->set_nice(0);
@@ -85,59 +85,59 @@ TEST_F(CpuInfoParserTest, Success) {
usage->set_host(0);
// This is a special line which is able to be parsed by the CpuInfoParser
- CpuInfo::Task* task1 = expected.add_tasks();
+ CpuInfoProto::Task* task1 = expected.add_tasks();
task1->set_pid(29438);
task1->set_tid(29438);
task1->set_user("rootabcdefghij");
task1->set_pr("20");
task1->set_ni(0);
task1->set_cpu(57.9);
- task1->set_s(CpuInfo::Task::STATUS_R);
+ task1->set_s(CpuInfoProto::Task::STATUS_R);
task1->set_virt("14M");
task1->set_res("3.8M");
- task1->set_pcy(CpuInfo::Task::POLICY_UNKNOWN);
+ task1->set_pcy(CpuInfoProto::Task::POLICY_UNKNOWN);
task1->set_cmd("top test");
task1->set_name("top");
- CpuInfo::Task* task2 = expected.add_tasks();
+ CpuInfoProto::Task* task2 = expected.add_tasks();
task2->set_pid(916);
task2->set_tid(916);
task2->set_user("system");
task2->set_pr("18");
task2->set_ni(-2);
task2->set_cpu(1.4);
- task2->set_s(CpuInfo::Task::STATUS_S);
+ task2->set_s(CpuInfoProto::Task::STATUS_S);
task2->set_virt("4.6G");
task2->set_res("404M");
- task2->set_pcy(CpuInfo::Task::POLICY_fg);
+ task2->set_pcy(CpuInfoProto::Task::POLICY_fg);
task2->set_cmd("system_server");
task2->set_name("system_server");
- CpuInfo::Task* task3 = expected.add_tasks();
+ CpuInfoProto::Task* task3 = expected.add_tasks();
task3->set_pid(28);
task3->set_tid(28);
task3->set_user("root");
task3->set_pr("-2");
task3->set_ni(0);
task3->set_cpu(1.4);
- task3->set_s(CpuInfo::Task::STATUS_S);
+ task3->set_s(CpuInfoProto::Task::STATUS_S);
task3->set_virt("0");
task3->set_res("0");
- task3->set_pcy(CpuInfo::Task::POLICY_bg);
+ task3->set_pcy(CpuInfoProto::Task::POLICY_bg);
task3->set_cmd("rcuc/3");
task3->set_name("[rcuc/3]");
- CpuInfo::Task* task4 = expected.add_tasks();
+ CpuInfoProto::Task* task4 = expected.add_tasks();
task4->set_pid(27);
task4->set_tid(27);
task4->set_user("root");
task4->set_pr("RT");
task4->set_ni(0);
task4->set_cpu(1.4);
- task4->set_s(CpuInfo::Task::STATUS_S);
+ task4->set_s(CpuInfoProto::Task::STATUS_S);
task4->set_virt("0");
task4->set_res("0");
- task4->set_pcy(CpuInfo::Task::POLICY_ta);
+ task4->set_pcy(CpuInfoProto::Task::POLICY_ta);
task4->set_cmd("migration/3");
task4->set_name("[migration/3]");
diff --git a/cmds/incident_helper/tests/KernelWakesParser_test.cpp b/cmds/incident_helper/tests/KernelWakesParser_test.cpp
index a98c62bd6024..f92d81361eab 100644
--- a/cmds/incident_helper/tests/KernelWakesParser_test.cpp
+++ b/cmds/incident_helper/tests/KernelWakesParser_test.cpp
@@ -52,14 +52,14 @@ protected:
TEST_F(KernelWakesParserTest, Short) {
const string testFile = kTestDataPath + "kernel_wakeups_short.txt";
KernelWakesParser parser;
- KernelWakeSources expected;
+ KernelWakeSourcesProto expected;
- WakeupSourceProto* record1 = expected.add_wakeup_sources();
+ KernelWakeSourcesProto::WakeupSource* record1 = expected.add_wakeup_sources();
record1->set_name("ab");
record1->set_active_count(8);
record1->set_last_change(123456123456LL);
- WakeupSourceProto* record2 = expected.add_wakeup_sources();
+ KernelWakeSourcesProto::WakeupSource* record2 = expected.add_wakeup_sources();
record2->set_name("df");
record2->set_active_count(143);
record2->set_last_change(0LL);
@@ -76,9 +76,9 @@ TEST_F(KernelWakesParserTest, Short) {
TEST_F(KernelWakesParserTest, Normal) {
const string testFile = kTestDataPath + "kernel_wakeups.txt";
KernelWakesParser parser;
- KernelWakeSources expected;
+ KernelWakeSourcesProto expected;
- WakeupSourceProto* record1 = expected.add_wakeup_sources();
+ KernelWakeSourcesProto::WakeupSource* record1 = expected.add_wakeup_sources();
record1->set_name("ipc000000ab_ATFWD-daemon");
record1->set_active_count(8);
record1->set_event_count(8);
@@ -90,7 +90,7 @@ TEST_F(KernelWakesParserTest, Normal) {
record1->set_last_change(131348LL);
record1->set_prevent_suspend_time(0LL);
- WakeupSourceProto* record2 = expected.add_wakeup_sources();
+ KernelWakeSourcesProto::WakeupSource* record2 = expected.add_wakeup_sources();
record2->set_name("ipc000000aa_ATFWD-daemon");
record2->set_active_count(143);
record2->set_event_count(143);
diff --git a/cmds/incident_helper/tests/PageTypeInfoParser_test.cpp b/cmds/incident_helper/tests/PageTypeInfoParser_test.cpp
index a9e6e816c6c5..9bad7be4a07e 100644
--- a/cmds/incident_helper/tests/PageTypeInfoParser_test.cpp
+++ b/cmds/incident_helper/tests/PageTypeInfoParser_test.cpp
@@ -52,12 +52,12 @@ protected:
TEST_F(PageTypeInfoParserTest, Success) {
const string testFile = kTestDataPath + "pagetypeinfo.txt";
PageTypeInfoParser parser;
- PageTypeInfo expected;
+ PageTypeInfoProto expected;
expected.set_page_block_order(10);
expected.set_pages_per_block(1024);
- MigrateTypeProto* mt1 = expected.add_migrate_types();
+ PageTypeInfoProto::MigrateType* mt1 = expected.add_migrate_types();
mt1->set_node(0);
mt1->set_zone("DMA");
mt1->set_type("Unmovable");
@@ -66,7 +66,7 @@ TEST_F(PageTypeInfoParserTest, Success) {
mt1->add_free_pages_count(arr1[i]);
}
- MigrateTypeProto* mt2 = expected.add_migrate_types();
+ PageTypeInfoProto::MigrateType* mt2 = expected.add_migrate_types();
mt2->set_node(0);
mt2->set_zone("Normal");
mt2->set_type("Reclaimable");
@@ -75,7 +75,7 @@ TEST_F(PageTypeInfoParserTest, Success) {
mt2->add_free_pages_count(arr2[i]);
}
- BlockProto* block1 = expected.add_blocks();
+ PageTypeInfoProto::Block* block1 = expected.add_blocks();
block1->set_node(0);
block1->set_zone("DMA");
block1->set_unmovable(74);
@@ -86,7 +86,7 @@ TEST_F(PageTypeInfoParserTest, Success) {
block1->set_isolate(0);
- BlockProto* block2 = expected.add_blocks();
+ PageTypeInfoProto::Block* block2 = expected.add_blocks();
block2->set_node(0);
block2->set_zone("Normal");
block2->set_unmovable(70);
diff --git a/cmds/incident_helper/tests/ProcrankParser_test.cpp b/cmds/incident_helper/tests/ProcrankParser_test.cpp
index 76b25d7f8f47..0b567aec9597 100644
--- a/cmds/incident_helper/tests/ProcrankParser_test.cpp
+++ b/cmds/incident_helper/tests/ProcrankParser_test.cpp
@@ -52,9 +52,9 @@ protected:
TEST_F(ProcrankParserTest, HasSwapInfo) {
const string testFile = kTestDataPath + "procrank.txt";
ProcrankParser parser;
- Procrank expected;
+ ProcrankProto expected;
- ProcessProto* process1 = expected.add_processes();
+ ProcrankProto::Process* process1 = expected.add_processes();
process1->set_pid(1119);
process1->set_vss(2607640);
process1->set_rss(339564);
@@ -66,7 +66,7 @@ TEST_F(ProcrankParserTest, HasSwapInfo) {
process1->set_zswap(10);
process1->set_cmdline("system_server");
- ProcessProto* process2 = expected.add_processes();
+ ProcrankProto::Process* process2 = expected.add_processes();
process2->set_pid(649);
process2->set_vss(11016);
process2->set_rss(1448);
@@ -78,7 +78,7 @@ TEST_F(ProcrankParserTest, HasSwapInfo) {
process2->set_zswap(75);
process2->set_cmdline("/vendor/bin/qseecomd");
- ProcessProto* total = expected.mutable_summary()->mutable_total();
+ ProcrankProto::Process* total = expected.mutable_summary()->mutable_total();
total->set_pss(1201993);
total->set_uss(935300);
total->set_swap(88164);
@@ -104,9 +104,9 @@ TEST_F(ProcrankParserTest, HasSwapInfo) {
TEST_F(ProcrankParserTest, NoSwapInfo) {
const string testFile = kTestDataPath + "procrank_short.txt";
ProcrankParser parser;
- Procrank expected;
+ ProcrankProto expected;
- ProcessProto* process1 = expected.add_processes();
+ ProcrankProto::Process* process1 = expected.add_processes();
process1->set_pid(1119);
process1->set_vss(2607640);
process1->set_rss(339564);
@@ -114,7 +114,7 @@ TEST_F(ProcrankParserTest, NoSwapInfo) {
process1->set_uss(114216);
process1->set_cmdline("system_server");
- ProcessProto* process2 = expected.add_processes();
+ ProcrankProto::Process* process2 = expected.add_processes();
process2->set_pid(649);
process2->set_vss(11016);
process2->set_rss(1448);
@@ -122,7 +122,7 @@ TEST_F(ProcrankParserTest, NoSwapInfo) {
process2->set_uss(48);
process2->set_cmdline("/vendor/bin/qseecomd");
- ProcessProto* total = expected.mutable_summary()->mutable_total();
+ ProcrankProto::Process* total = expected.mutable_summary()->mutable_total();
total->set_pss(1201993);
total->set_uss(935300);
total->set_cmdline("TOTAL");
diff --git a/cmds/incident_helper/tests/PsParser_test.cpp b/cmds/incident_helper/tests/PsParser_test.cpp
index 1f03a7f3a332..114d63472ffc 100644
--- a/cmds/incident_helper/tests/PsParser_test.cpp
+++ b/cmds/incident_helper/tests/PsParser_test.cpp
@@ -52,10 +52,10 @@ protected:
TEST_F(PsParserTest, Normal) {
const string testFile = kTestDataPath + "ps.txt";
PsParser parser;
- PsDumpProto expected;
- PsDumpProto got;
+ PsProto expected;
+ PsProto got;
- PsDumpProto::Process* record1 = expected.add_processes();
+ PsProto::Process* record1 = expected.add_processes();
record1->set_label("u:r:init:s0");
record1->set_user("root");
record1->set_pid(1);
@@ -65,16 +65,16 @@ TEST_F(PsParserTest, Normal) {
record1->set_rss(2636);
record1->set_wchan("SyS_epoll_wait");
record1->set_addr("0");
- record1->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record1->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record1->set_pri(19);
record1->set_ni(0);
record1->set_rtprio("-");
- record1->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record1->set_pcy(PsDumpProto::Process::POLICY_FG);
+ record1->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record1->set_pcy(PsProto::Process::POLICY_FG);
record1->set_time("00:00:01");
record1->set_cmd("init");
- PsDumpProto::Process* record2 = expected.add_processes();
+ PsProto::Process* record2 = expected.add_processes();
record2->set_label("u:r:kernel:s0");
record2->set_user("root");
record2->set_pid(2);
@@ -84,16 +84,16 @@ TEST_F(PsParserTest, Normal) {
record2->set_rss(0);
record2->set_wchan("kthreadd");
record2->set_addr("0");
- record2->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record2->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record2->set_pri(19);
record2->set_ni(0);
record2->set_rtprio("-");
- record2->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record2->set_pcy(PsDumpProto::Process::POLICY_FG);
+ record2->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record2->set_pcy(PsProto::Process::POLICY_FG);
record2->set_time("00:00:00");
record2->set_cmd("kthreadd");
- PsDumpProto::Process* record3 = expected.add_processes();
+ PsProto::Process* record3 = expected.add_processes();
record3->set_label("u:r:surfaceflinger:s0");
record3->set_user("system");
record3->set_pid(499);
@@ -103,16 +103,16 @@ TEST_F(PsParserTest, Normal) {
record3->set_rss(22024);
record3->set_wchan("futex_wait_queue_me");
record3->set_addr("0");
- record3->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record3->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record3->set_pri(42);
record3->set_ni(-9);
record3->set_rtprio("2");
- record3->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_FIFO);
- record3->set_pcy(PsDumpProto::Process::POLICY_FG);
+ record3->set_sch(PsProto_Process_SchedulingPolicy_SCH_FIFO);
+ record3->set_pcy(PsProto::Process::POLICY_FG);
record3->set_time("00:00:00");
record3->set_cmd("EventThread");
- PsDumpProto::Process* record4 = expected.add_processes();
+ PsProto::Process* record4 = expected.add_processes();
record4->set_label("u:r:hal_gnss_default:s0");
record4->set_user("gps");
record4->set_pid(670);
@@ -122,16 +122,16 @@ TEST_F(PsParserTest, Normal) {
record4->set_rss(7272);
record4->set_wchan("poll_schedule_timeout");
record4->set_addr("0");
- record4->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record4->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record4->set_pri(19);
record4->set_ni(0);
record4->set_rtprio("-");
- record4->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record4->set_pcy(PsDumpProto::Process::POLICY_FG);
+ record4->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record4->set_pcy(PsProto::Process::POLICY_FG);
record4->set_time("00:00:00");
record4->set_cmd("Loc_hal_worker");
- PsDumpProto::Process* record5 = expected.add_processes();
+ PsProto::Process* record5 = expected.add_processes();
record5->set_label("u:r:platform_app:s0:c512,c768");
record5->set_user("u0_a48");
record5->set_pid(1660);
@@ -141,16 +141,16 @@ TEST_F(PsParserTest, Normal) {
record5->set_rss(138328);
record5->set_wchan("binder_thread_read");
record5->set_addr("0");
- record5->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record5->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record5->set_pri(35);
record5->set_ni(-16);
record5->set_rtprio("-");
- record5->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record5->set_pcy(PsDumpProto::Process::POLICY_TA);
+ record5->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record5->set_pcy(PsProto::Process::POLICY_TA);
record5->set_time("00:00:00");
record5->set_cmd("HwBinder:1660_1");
- PsDumpProto::Process* record6 = expected.add_processes();
+ PsProto::Process* record6 = expected.add_processes();
record6->set_label("u:r:perfd:s0");
record6->set_user("root");
record6->set_pid(1939);
@@ -160,16 +160,16 @@ TEST_F(PsParserTest, Normal) {
record6->set_rss(2088);
record6->set_wchan("__skb_recv_datagram");
record6->set_addr("7b9782fd14");
- record6->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record6->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record6->set_pri(19);
record6->set_ni(0);
record6->set_rtprio("-");
- record6->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record6->set_pcy(PsDumpProto::Process::POLICY_UNKNOWN);
+ record6->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record6->set_pcy(PsProto::Process::POLICY_UNKNOWN);
record6->set_time("00:00:00");
record6->set_cmd("perfd");
- PsDumpProto::Process* record7 = expected.add_processes();
+ PsProto::Process* record7 = expected.add_processes();
record7->set_label("u:r:perfd:s0");
record7->set_user("root");
record7->set_pid(1939);
@@ -179,16 +179,16 @@ TEST_F(PsParserTest, Normal) {
record7->set_rss(2088);
record7->set_wchan("do_sigtimedwait");
record7->set_addr("7b9782ff6c");
- record7->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record7->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record7->set_pri(19);
record7->set_ni(0);
record7->set_rtprio("-");
- record7->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record7->set_pcy(PsDumpProto::Process::POLICY_UNKNOWN);
+ record7->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record7->set_pcy(PsProto::Process::POLICY_UNKNOWN);
record7->set_time("00:00:00");
record7->set_cmd("POSIX timer 0");
- PsDumpProto::Process* record8 = expected.add_processes();
+ PsProto::Process* record8 = expected.add_processes();
record8->set_label("u:r:shell:s0");
record8->set_user("shell");
record8->set_pid(2645);
@@ -198,12 +198,12 @@ TEST_F(PsParserTest, Normal) {
record8->set_rss(2972);
record8->set_wchan("0");
record8->set_addr("7f67a2f8b4");
- record8->set_s(PsDumpProto_Process_ProcessStateCode_STATE_R);
+ record8->set_s(PsProto_Process_ProcessStateCode_STATE_R);
record8->set_pri(19);
record8->set_ni(0);
record8->set_rtprio("-");
- record8->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record8->set_pcy(PsDumpProto::Process::POLICY_FG);
+ record8->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record8->set_pcy(PsProto::Process::POLICY_FG);
record8->set_time("00:00:00");
record8->set_cmd("ps");
@@ -221,8 +221,8 @@ TEST_F(PsParserTest, Normal) {
} else {
int n = got.processes_size();
for (int i = 0; i < n; i++) {
- PsDumpProto::Process g = got.processes(i);
- PsDumpProto::Process e = expected.processes(i);
+ PsProto::Process g = got.processes(i);
+ PsProto::Process e = expected.processes(i);
if (g.label() != e.label()) {
fprintf(stderr, "prcs[%d]: Invalid label. Got %s, want %s\n", i, g.label().c_str(), e.label().c_str());
diff --git a/cmds/incidentd/.clang-format b/cmds/incidentd/.clang-format
new file mode 100644
index 000000000000..6fa5b474b715
--- /dev/null
+++ b/cmds/incidentd/.clang-format
@@ -0,0 +1,17 @@
+BasedOnStyle: Google
+AllowShortIfStatementsOnASingleLine: true
+AllowShortFunctionsOnASingleLine: true
+AllowShortLoopsOnASingleLine: true
+BinPackArguments: true
+BinPackParameters: true
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+ContinuationIndentWidth: 8
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+AccessModifierOffset: -4
+IncludeCategories:
+ - Regex: '^"Log\.h"'
+ Priority: -1
diff --git a/cmds/incidentd/Android.mk b/cmds/incidentd/Android.mk
index 2b00d9e6a596..d2d24c89449a 100644
--- a/cmds/incidentd/Android.mk
+++ b/cmds/incidentd/Android.mk
@@ -32,7 +32,7 @@ LOCAL_SRC_FILES := \
src/Privacy.cpp \
src/Reporter.cpp \
src/Section.cpp \
- src/io_util.cpp \
+ src/incidentd_util.cpp \
src/main.cpp \
src/report_directory.cpp
@@ -56,6 +56,7 @@ LOCAL_SHARED_LIBRARIES := \
libcutils \
libincident \
liblog \
+ libprotobuf-cpp-lite \
libprotoutil \
libselinux \
libservices \
@@ -115,7 +116,7 @@ LOCAL_SRC_FILES := \
src/Privacy.cpp \
src/Reporter.cpp \
src/Section.cpp \
- src/io_util.cpp \
+ src/incidentd_util.cpp \
src/report_directory.cpp \
tests/section_list.cpp \
tests/PrivacyBuffer_test.cpp \
diff --git a/cmds/incidentd/OWNERS b/cmds/incidentd/OWNERS
new file mode 100644
index 000000000000..1a68a32c4308
--- /dev/null
+++ b/cmds/incidentd/OWNERS
@@ -0,0 +1,2 @@
+jinyithu@google.com
+kwekua@google.com
diff --git a/cmds/incidentd/README.md b/cmds/incidentd/README.md
index 71c6deb18aac..1730a6401254 100644
--- a/cmds/incidentd/README.md
+++ b/cmds/incidentd/README.md
@@ -20,4 +20,8 @@ Run the test via AndroidTest.xml
```
root$ atest incidentd_test
-``` \ No newline at end of file
+```
+
+Use clang-format to style the file
+
+clang-format -style=file -i <file list> \ No newline at end of file
diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp
index 0fff4e6dc4a0..883924c83d82 100644
--- a/cmds/incidentd/src/FdBuffer.cpp
+++ b/cmds/incidentd/src/FdBuffer.cpp
@@ -13,8 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "FdBuffer.h"
@@ -26,30 +25,16 @@
#include <unistd.h>
#include <wait.h>
-const bool DEBUG = false;
-const ssize_t BUFFER_SIZE = 16 * 1024; // 16 KB
-const ssize_t MAX_BUFFER_COUNT = 256; // 4 MB max
+const ssize_t BUFFER_SIZE = 16 * 1024; // 16 KB
+const ssize_t MAX_BUFFER_COUNT = 256; // 4 MB max
FdBuffer::FdBuffer()
- :mBuffer(BUFFER_SIZE),
- mStartTime(-1),
- mFinishTime(-1),
- mTimedOut(false),
- mTruncated(false)
-{
-}
+ : mBuffer(BUFFER_SIZE), mStartTime(-1), mFinishTime(-1), mTimedOut(false), mTruncated(false) {}
-FdBuffer::~FdBuffer()
-{
-}
+FdBuffer::~FdBuffer() {}
-status_t
-FdBuffer::read(int fd, int64_t timeout)
-{
- struct pollfd pfds = {
- .fd = fd,
- .events = POLLIN
- };
+status_t FdBuffer::read(int fd, int64_t timeout) {
+ struct pollfd pfds = {.fd = fd, .events = POLLIN};
mStartTime = uptimeMillis();
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
@@ -63,22 +48,22 @@ FdBuffer::read(int fd, int64_t timeout)
int64_t remainingTime = (mStartTime + timeout) - uptimeMillis();
if (remainingTime <= 0) {
- if (DEBUG) ALOGD("timed out due to long read");
+ VLOG("timed out due to long read");
mTimedOut = true;
break;
}
int count = poll(&pfds, 1, remainingTime);
if (count == 0) {
- if (DEBUG) ALOGD("timed out due to block calling poll");
+ VLOG("timed out due to block calling poll");
mTimedOut = true;
break;
} else if (count < 0) {
- if (DEBUG) ALOGD("poll failed: %s", strerror(errno));
+ VLOG("poll failed: %s", strerror(errno));
return -errno;
} else {
if ((pfds.revents & POLLERR) != 0) {
- if (DEBUG) ALOGD("return event has error %s", strerror(errno));
+ VLOG("return event has error %s", strerror(errno));
return errno != 0 ? -errno : UNKNOWN_ERROR;
} else {
ssize_t amt = ::read(fd, mBuffer.writeBuffer(), mBuffer.currentToWrite());
@@ -86,7 +71,7 @@ FdBuffer::read(int fd, int64_t timeout)
if (errno == EAGAIN || errno == EWOULDBLOCK) {
continue;
} else {
- if (DEBUG) ALOGD("Fail to read %d: %s", fd, strerror(errno));
+ VLOG("Fail to read %d: %s", fd, strerror(errno));
return -errno;
}
} else if (amt == 0) {
@@ -100,13 +85,12 @@ FdBuffer::read(int fd, int64_t timeout)
return NO_ERROR;
}
-status_t
-FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeoutMs, const bool isSysfs)
-{
+status_t FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeoutMs,
+ const bool isSysfs) {
struct pollfd pfds[] = {
- { .fd = fd, .events = POLLIN },
- { .fd = toFd, .events = POLLOUT },
- { .fd = fromFd, .events = POLLIN },
+ {.fd = fd, .events = POLLIN},
+ {.fd = toFd, .events = POLLOUT},
+ {.fd = fromFd, .events = POLLIN},
};
mStartTime = uptimeMillis();
@@ -131,7 +115,7 @@ FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeou
int64_t remainingTime = (mStartTime + timeoutMs) - uptimeMillis();
if (remainingTime <= 0) {
- if (DEBUG) ALOGD("timed out due to long read");
+ VLOG("timed out due to long read");
mTimedOut = true;
break;
}
@@ -139,11 +123,11 @@ FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeou
// wait for any pfds to be ready to perform IO
int count = poll(pfds, 3, remainingTime);
if (count == 0) {
- if (DEBUG) ALOGD("timed out due to block calling poll");
+ VLOG("timed out due to block calling poll");
mTimedOut = true;
break;
} else if (count < 0) {
- if (DEBUG) ALOGD("Fail to poll: %s", strerror(errno));
+ VLOG("Fail to poll: %s", strerror(errno));
return -errno;
}
@@ -151,10 +135,10 @@ FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeou
for (int i = 0; i < 3; ++i) {
if ((pfds[i].revents & POLLERR) != 0) {
if (i == 0 && isSysfs) {
- if (DEBUG) ALOGD("fd %d is sysfs, ignore its POLLERR return value", fd);
+ VLOG("fd %d is sysfs, ignore its POLLERR return value", fd);
continue;
}
- if (DEBUG) ALOGD("fd[%d]=%d returns error events: %s", i, fd, strerror(errno));
+ VLOG("fd[%d]=%d returns error events: %s", i, fd, strerror(errno));
return errno != 0 ? -errno : UNKNOWN_ERROR;
}
}
@@ -169,9 +153,9 @@ FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeou
}
if (amt < 0) {
if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
- if (DEBUG) ALOGD("Fail to read fd %d: %s", fd, strerror(errno));
+ VLOG("Fail to read fd %d: %s", fd, strerror(errno));
return -errno;
- } // otherwise just continue
+ } // otherwise just continue
} else if (amt == 0) { // reach EOF so don't have to poll pfds[0].
::close(pfds[0].fd);
pfds[0].fd = -1;
@@ -191,9 +175,9 @@ FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeou
}
if (amt < 0) {
if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
- if (DEBUG) ALOGD("Fail to write toFd %d: %s", toFd, strerror(errno));
+ VLOG("Fail to write toFd %d: %s", toFd, strerror(errno));
return -errno;
- } // otherwise just continue
+ } // otherwise just continue
} else {
wpos += amt;
cirSize -= amt;
@@ -218,9 +202,9 @@ FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeou
ssize_t amt = ::read(fromFd, mBuffer.writeBuffer(), mBuffer.currentToWrite());
if (amt < 0) {
if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
- if (DEBUG) ALOGD("Fail to read fromFd %d: %s", fromFd, strerror(errno));
+ VLOG("Fail to read fromFd %d: %s", fromFd, strerror(errno));
return -errno;
- } // otherwise just continue
+ } // otherwise just continue
} else if (amt == 0) {
break;
} else {
@@ -232,14 +216,6 @@ FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeou
return NO_ERROR;
}
-size_t
-FdBuffer::size() const
-{
- return mBuffer.size();
-}
+size_t FdBuffer::size() const { return mBuffer.size(); }
-EncodedBuffer::iterator
-FdBuffer::data() const
-{
- return mBuffer.begin();
-}
+EncodedBuffer::iterator FdBuffer::data() const { return mBuffer.begin(); }
diff --git a/cmds/incidentd/src/FdBuffer.h b/cmds/incidentd/src/FdBuffer.h
index 48dc855e71b2..5bfa0938f5e8 100644
--- a/cmds/incidentd/src/FdBuffer.h
+++ b/cmds/incidentd/src/FdBuffer.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#ifndef FD_BUFFER_H
#define FD_BUFFER_H
@@ -27,8 +28,7 @@ using namespace std;
/**
* Reads a file into a buffer, and then writes that data to an FdSet.
*/
-class FdBuffer
-{
+class FdBuffer {
public:
FdBuffer();
~FdBuffer();
@@ -50,7 +50,8 @@ public:
*
* Poll will return POLLERR if fd is from sysfs, handle this edge case.
*/
- status_t readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeoutMs, const bool isSysfs=false);
+ status_t readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeoutMs,
+ const bool isSysfs = false);
/**
* Whether we timed out.
@@ -90,4 +91,4 @@ private:
bool mTruncated;
};
-#endif // FD_BUFFER_H
+#endif // FD_BUFFER_H
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index 654036ec6ab7..9ae624094dca 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -13,15 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "IncidentService.h"
+#include "FdBuffer.h"
+#include "PrivacyBuffer.h"
#include "Reporter.h"
+#include "incidentd_util.h"
+#include "section_list.h"
#include <binder/IPCThreadState.h>
+#include <binder/IResultReceiver.h>
#include <binder/IServiceManager.h>
+#include <binder/IShellCallback.h>
#include <cutils/log.h>
#include <private/android_filesystem_config.h>
#include <utils/Looper.h>
@@ -29,11 +34,9 @@
#include <unistd.h>
using namespace android;
+using namespace android::base;
-enum {
- WHAT_RUN_REPORT = 1,
- WHAT_SEND_BACKLOG_TO_DROPBOX = 2
-};
+enum { WHAT_RUN_REPORT = 1, WHAT_SEND_BACKLOG_TO_DROPBOX = 2 };
//#define DEFAULT_BACKLOG_DELAY_NS (1000000000LL * 60 * 5)
#define DEFAULT_BACKLOG_DELAY_NS (1000000000LL)
@@ -42,9 +45,7 @@ enum {
String16 const DUMP_PERMISSION("android.permission.DUMP");
String16 const USAGE_STATS_PERMISSION("android.permission.PACKAGE_USAGE_STATS");
-static Status
-checkIncidentPermissions(const IncidentReportArgs& args)
-{
+static Status checkIncidentPermissions(const IncidentReportArgs& args) {
uid_t callingUid = IPCThreadState::self()->getCallingUid();
pid_t callingPid = IPCThreadState::self()->getCallingPid();
if (callingUid == AID_ROOT || callingUid == AID_SHELL) {
@@ -55,14 +56,16 @@ checkIncidentPermissions(const IncidentReportArgs& args)
// checking calling permission.
if (!checkCallingPermission(DUMP_PERMISSION)) {
ALOGW("Calling pid %d and uid %d does not have permission: android.permission.DUMP",
- callingPid, callingUid);
- return Status::fromExceptionCode(Status::EX_SECURITY,
+ callingPid, callingUid);
+ return Status::fromExceptionCode(
+ Status::EX_SECURITY,
"Calling process does not have permission: android.permission.DUMP");
}
if (!checkCallingPermission(USAGE_STATS_PERMISSION)) {
ALOGW("Calling pid %d and uid %d does not have permission: android.permission.USAGE_STATS",
- callingPid, callingUid);
- return Status::fromExceptionCode(Status::EX_SECURITY,
+ callingPid, callingUid);
+ return Status::fromExceptionCode(
+ Status::EX_SECURITY,
"Calling process does not have permission: android.permission.USAGE_STATS");
}
@@ -71,40 +74,34 @@ checkIncidentPermissions(const IncidentReportArgs& args)
case DEST_LOCAL:
if (callingUid != AID_SHELL && callingUid != AID_ROOT) {
ALOGW("Calling pid %d and uid %d does not have permission to get local data.",
- callingPid, callingUid);
- return Status::fromExceptionCode(Status::EX_SECURITY,
- "Calling process does not have permission to get local data.");
+ callingPid, callingUid);
+ return Status::fromExceptionCode(
+ Status::EX_SECURITY,
+ "Calling process does not have permission to get local data.");
}
case DEST_EXPLICIT:
- if (callingUid != AID_SHELL && callingUid != AID_ROOT &&
- callingUid != AID_STATSD && callingUid != AID_SYSTEM) {
+ if (callingUid != AID_SHELL && callingUid != AID_ROOT && callingUid != AID_STATSD &&
+ callingUid != AID_SYSTEM) {
ALOGW("Calling pid %d and uid %d does not have permission to get explicit data.",
- callingPid, callingUid);
- return Status::fromExceptionCode(Status::EX_SECURITY,
- "Calling process does not have permission to get explicit data.");
+ callingPid, callingUid);
+ return Status::fromExceptionCode(
+ Status::EX_SECURITY,
+ "Calling process does not have permission to get explicit data.");
}
}
return Status::ok();
}
// ================================================================================
-ReportRequestQueue::ReportRequestQueue()
-{
-}
+ReportRequestQueue::ReportRequestQueue() {}
-ReportRequestQueue::~ReportRequestQueue()
-{
-}
+ReportRequestQueue::~ReportRequestQueue() {}
-void
-ReportRequestQueue::addRequest(const sp<ReportRequest>& request)
-{
+void ReportRequestQueue::addRequest(const sp<ReportRequest>& request) {
unique_lock<mutex> lock(mLock);
mQueue.push_back(request);
}
-sp<ReportRequest>
-ReportRequestQueue::getNextRequest()
-{
+sp<ReportRequest> ReportRequestQueue::getNextRequest() {
unique_lock<mutex> lock(mLock);
if (mQueue.empty()) {
return NULL;
@@ -115,22 +112,13 @@ ReportRequestQueue::getNextRequest()
}
}
-
// ================================================================================
ReportHandler::ReportHandler(const sp<Looper>& handlerLooper, const sp<ReportRequestQueue>& queue)
- :mBacklogDelay(DEFAULT_BACKLOG_DELAY_NS),
- mHandlerLooper(handlerLooper),
- mQueue(queue)
-{
-}
+ : mBacklogDelay(DEFAULT_BACKLOG_DELAY_NS), mHandlerLooper(handlerLooper), mQueue(queue) {}
-ReportHandler::~ReportHandler()
-{
-}
+ReportHandler::~ReportHandler() {}
-void
-ReportHandler::handleMessage(const Message& message)
-{
+void ReportHandler::handleMessage(const Message& message) {
switch (message.what) {
case WHAT_RUN_REPORT:
run_report();
@@ -141,33 +129,24 @@ ReportHandler::handleMessage(const Message& message)
}
}
-void
-ReportHandler::scheduleRunReport(const sp<ReportRequest>& request)
-{
+void ReportHandler::scheduleRunReport(const sp<ReportRequest>& request) {
mQueue->addRequest(request);
mHandlerLooper->removeMessages(this, WHAT_RUN_REPORT);
mHandlerLooper->sendMessage(this, Message(WHAT_RUN_REPORT));
}
-void
-ReportHandler::scheduleSendBacklogToDropbox()
-{
+void ReportHandler::scheduleSendBacklogToDropbox() {
unique_lock<mutex> lock(mLock);
mBacklogDelay = DEFAULT_BACKLOG_DELAY_NS;
schedule_send_backlog_to_dropbox_locked();
}
-void
-ReportHandler::schedule_send_backlog_to_dropbox_locked()
-{
+void ReportHandler::schedule_send_backlog_to_dropbox_locked() {
mHandlerLooper->removeMessages(this, WHAT_SEND_BACKLOG_TO_DROPBOX);
- mHandlerLooper->sendMessageDelayed(mBacklogDelay, this,
- Message(WHAT_SEND_BACKLOG_TO_DROPBOX));
+ mHandlerLooper->sendMessageDelayed(mBacklogDelay, this, Message(WHAT_SEND_BACKLOG_TO_DROPBOX));
}
-void
-ReportHandler::run_report()
-{
+void ReportHandler::run_report() {
sp<Reporter> reporter = new Reporter();
// Merge all of the requests into one that has all of the
@@ -190,15 +169,13 @@ ReportHandler::run_report()
}
}
-void
-ReportHandler::send_backlog_to_dropbox()
-{
+void ReportHandler::send_backlog_to_dropbox() {
if (Reporter::upload_backlog() == Reporter::REPORT_NEEDS_DROPBOX) {
// There was a failure. Exponential backoff.
unique_lock<mutex> lock(mLock);
mBacklogDelay *= 2;
ALOGI("Error sending to dropbox. Trying again in %lld minutes",
- (mBacklogDelay / (1000000000LL * 60)));
+ (mBacklogDelay / (1000000000LL * 60)));
schedule_send_backlog_to_dropbox_locked();
} else {
mBacklogDelay = DEFAULT_BACKLOG_DELAY_NS;
@@ -207,18 +184,13 @@ ReportHandler::send_backlog_to_dropbox()
// ================================================================================
IncidentService::IncidentService(const sp<Looper>& handlerLooper)
- :mQueue(new ReportRequestQueue())
-{
+ : mQueue(new ReportRequestQueue()) {
mHandler = new ReportHandler(handlerLooper, mQueue);
}
-IncidentService::~IncidentService()
-{
-}
+IncidentService::~IncidentService() {}
-Status
-IncidentService::reportIncident(const IncidentReportArgs& args)
-{
+Status IncidentService::reportIncident(const IncidentReportArgs& args) {
ALOGI("reportIncident");
Status status = checkIncidentPermissions(args);
@@ -231,10 +203,9 @@ IncidentService::reportIncident(const IncidentReportArgs& args)
return Status::ok();
}
-Status
-IncidentService::reportIncidentToStream(const IncidentReportArgs& args,
- const sp<IIncidentReportStatusListener>& listener, const unique_fd& stream)
-{
+Status IncidentService::reportIncidentToStream(const IncidentReportArgs& args,
+ const sp<IIncidentReportStatusListener>& listener,
+ const unique_fd& stream) {
ALOGI("reportIncidentToStream");
Status status = checkIncidentPermissions(args);
@@ -252,12 +223,10 @@ IncidentService::reportIncidentToStream(const IncidentReportArgs& args,
return Status::ok();
}
-Status
-IncidentService::systemRunning()
-{
+Status IncidentService::systemRunning() {
if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
return Status::fromExceptionCode(Status::EX_SECURITY,
- "Only system uid can call systemRunning");
+ "Only system uid can call systemRunning");
}
// When system_server is up and running, schedule the dropbox task to run.
@@ -266,3 +235,120 @@ IncidentService::systemRunning()
return Status::ok();
}
+/**
+ * Implement our own because the default binder implementation isn't
+ * properly handling SHELL_COMMAND_TRANSACTION.
+ */
+status_t IncidentService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags) {
+ status_t err;
+
+ switch (code) {
+ case SHELL_COMMAND_TRANSACTION: {
+ int in = data.readFileDescriptor();
+ int out = data.readFileDescriptor();
+ int err = data.readFileDescriptor();
+ int argc = data.readInt32();
+ Vector<String8> args;
+ for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
+ args.add(String8(data.readString16()));
+ }
+ sp<IShellCallback> shellCallback = IShellCallback::asInterface(data.readStrongBinder());
+ sp<IResultReceiver> resultReceiver =
+ IResultReceiver::asInterface(data.readStrongBinder());
+
+ FILE* fin = fdopen(in, "r");
+ FILE* fout = fdopen(out, "w");
+ FILE* ferr = fdopen(err, "w");
+
+ if (fin == NULL || fout == NULL || ferr == NULL) {
+ resultReceiver->send(NO_MEMORY);
+ } else {
+ err = command(fin, fout, ferr, args);
+ resultReceiver->send(err);
+ }
+
+ if (fin != NULL) {
+ fflush(fin);
+ fclose(fin);
+ }
+ if (fout != NULL) {
+ fflush(fout);
+ fclose(fout);
+ }
+ if (fout != NULL) {
+ fflush(ferr);
+ fclose(ferr);
+ }
+
+ return NO_ERROR;
+ }
+ default: { return BnIncidentManager::onTransact(code, data, reply, flags); }
+ }
+}
+
+status_t IncidentService::command(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
+ const int argCount = args.size();
+
+ if (argCount >= 1) {
+ if (!args[0].compare(String8("privacy"))) {
+ return cmd_privacy(in, out, err, args);
+ }
+ }
+ return cmd_help(out);
+}
+
+status_t IncidentService::cmd_help(FILE* out) {
+ fprintf(out, "usage: adb shell cmd incident privacy print <section_id>\n");
+ fprintf(out, "usage: adb shell cmd incident privacy parse <section_id> < proto.txt\n");
+ fprintf(out, " Prints/parses for the section id.\n");
+ return NO_ERROR;
+}
+
+static void printPrivacy(const Privacy* p, FILE* out, String8 indent) {
+ if (p == NULL) return;
+ fprintf(out, "%sid:%d, type:%d, dest:%d\n", indent.string(), p->field_id, p->type, p->dest);
+ if (p->children == NULL) return;
+ for (int i = 0; p->children[i] != NULL; i++) { // NULL-terminated.
+ printPrivacy(p->children[i], out, indent + " ");
+ }
+}
+
+status_t IncidentService::cmd_privacy(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
+ const int argCount = args.size();
+ if (argCount >= 3) {
+ String8 opt = args[1];
+ int sectionId = atoi(args[2].string());
+
+ const Privacy* p = get_privacy_of_section(sectionId);
+ if (p == NULL) {
+ fprintf(err, "Can't find section id %d\n", sectionId);
+ return NO_ERROR;
+ }
+ fprintf(err, "Get privacy for %d\n", sectionId);
+ if (opt == "print") {
+ printPrivacy(p, out, String8(""));
+ } else if (opt == "parse") {
+ FdBuffer buf;
+ status_t error = buf.read(fileno(in), 60000);
+ if (error != NO_ERROR) {
+ fprintf(err, "Error reading from stdin\n");
+ return error;
+ }
+ fprintf(err, "Read %zu bytes\n", buf.size());
+ auto data = buf.data();
+ PrivacyBuffer pBuf(p, data);
+
+ PrivacySpec spec = PrivacySpec::new_spec(argCount > 3 ? atoi(args[3]) : -1);
+ error = pBuf.strip(spec);
+ if (error != NO_ERROR) {
+ fprintf(err, "Error strip pii fields with spec %d\n", spec.dest);
+ return error;
+ }
+ return pBuf.flush(fileno(out));
+ }
+ } else {
+ return cmd_help(out);
+ }
+ return NO_ERROR;
+}
diff --git a/cmds/incidentd/src/IncidentService.h b/cmds/incidentd/src/IncidentService.h
index d6f33dfb1a86..3c665076bebc 100644
--- a/cmds/incidentd/src/IncidentService.h
+++ b/cmds/incidentd/src/IncidentService.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#ifndef INCIDENT_SERVICE_H
#define INCIDENT_SERVICE_H
@@ -32,8 +33,7 @@ using namespace android::os;
using namespace std;
// ================================================================================
-class ReportRequestQueue : public virtual RefBase
-{
+class ReportRequestQueue : public virtual RefBase {
public:
ReportRequestQueue();
virtual ~ReportRequestQueue();
@@ -46,10 +46,8 @@ private:
deque<sp<ReportRequest> > mQueue;
};
-
// ================================================================================
-class ReportHandler : public MessageHandler
-{
+class ReportHandler : public MessageHandler {
public:
ReportHandler(const sp<Looper>& handlerLooper, const sp<ReportRequestQueue>& queue);
virtual ~ReportHandler();
@@ -89,7 +87,6 @@ private:
void send_backlog_to_dropbox();
};
-
// ================================================================================
class IncidentService : public BnIncidentManager {
public:
@@ -99,14 +96,29 @@ public:
virtual Status reportIncident(const IncidentReportArgs& args);
virtual Status reportIncidentToStream(const IncidentReportArgs& args,
- const sp<IIncidentReportStatusListener>& listener, const unique_fd& stream);
+ const sp<IIncidentReportStatusListener>& listener,
+ const unique_fd& stream);
virtual Status systemRunning();
+ // Implement commands for debugging purpose.
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags) override;
+ virtual status_t command(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
+
private:
sp<ReportRequestQueue> mQueue;
sp<ReportHandler> mHandler;
-};
+ /**
+ * Commands print out help.
+ */
+ status_t cmd_help(FILE* out);
+
+ /**
+ * Commands related to privacy filtering.
+ */
+ status_t cmd_privacy(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
+};
-#endif // INCIDENT_SERVICE_H
+#endif // INCIDENT_SERVICE_H
diff --git a/cmds/incidentd/src/io_util.cpp b/cmds/incidentd/src/Log.h
index 90f543e30ff7..46efbd1fb7d0 100644
--- a/cmds/incidentd/src/io_util.cpp
+++ b/cmds/incidentd/src/Log.h
@@ -14,33 +14,21 @@
* limitations under the License.
*/
-#define LOG_TAG "incidentd"
-
-#include "io_util.h"
-
-#include <unistd.h>
-
-status_t write_all(int fd, uint8_t const* buf, size_t size)
-{
- while (size > 0) {
- ssize_t amt = TEMP_FAILURE_RETRY(::write(fd, buf, size));
- if (amt < 0) {
- return -errno;
- }
- size -= amt;
- buf += amt;
- }
- return NO_ERROR;
-}
-
-Fpipe::Fpipe() {}
-
-Fpipe::~Fpipe() { close(); }
+/*
+ * This file must be included at the top of the file. Other header files
+ * occasionally include log.h, and if LOG_TAG isn't set when that happens
+ * we'll get a preprocesser error when we try to define it here.
+ */
-bool Fpipe::close() { return !(::close(mFds[0]) || ::close(mFds[1])); }
+#pragma once
-bool Fpipe::init() { return pipe(mFds) != -1; }
+#define LOG_TAG "incidentd"
+#define DEBUG false
-int Fpipe::readFd() const { return mFds[0]; }
+#include <log/log.h>
-int Fpipe::writeFd() const { return mFds[1]; }
+// Use the local value to turn on/off debug logs instead of using log.tag.properties.
+// The advantage is that in production compiler can remove the logging code if the local
+// DEBUG/VERBOSE is false.
+#define VLOG(...) \
+ if (DEBUG) ALOGD(__VA_ARGS__); \ No newline at end of file
diff --git a/cmds/incidentd/src/Privacy.cpp b/cmds/incidentd/src/Privacy.cpp
index 3f0e331c8b55..c42a87b64a73 100644
--- a/cmds/incidentd/src/Privacy.cpp
+++ b/cmds/incidentd/src/Privacy.cpp
@@ -21,10 +21,9 @@
uint64_t encode_field_id(const Privacy* p) { return (uint64_t)p->type << 32 | p->field_id; }
-const Privacy* lookup(const Privacy* p, uint32_t fieldId)
-{
+const Privacy* lookup(const Privacy* p, uint32_t fieldId) {
if (p->children == NULL) return NULL;
- for (int i=0; p->children[i] != NULL; i++) { // NULL-terminated.
+ for (int i = 0; p->children[i] != NULL; i++) { // NULL-terminated.
if (p->children[i]->field_id == fieldId) return p->children[i];
// Incident section gen tool guarantees field ids in ascending order.
if (p->children[i]->field_id > fieldId) return NULL;
@@ -32,52 +31,37 @@ const Privacy* lookup(const Privacy* p, uint32_t fieldId)
return NULL;
}
-static bool allowDest(const uint8_t dest, const uint8_t policy)
-{
+static bool allowDest(const uint8_t dest, const uint8_t policy) {
switch (policy) {
- case android::os::DEST_LOCAL:
- return dest == android::os::DEST_LOCAL;
- case android::os::DEST_EXPLICIT:
- case DEST_UNSET:
- return dest == android::os::DEST_LOCAL ||
- dest == android::os::DEST_EXPLICIT ||
- dest == DEST_UNSET;
- case android::os::DEST_AUTOMATIC:
- return true;
- default:
- return false;
+ case android::os::DEST_LOCAL:
+ return dest == android::os::DEST_LOCAL;
+ case android::os::DEST_EXPLICIT:
+ case DEST_UNSET:
+ return dest == android::os::DEST_LOCAL || dest == android::os::DEST_EXPLICIT ||
+ dest == DEST_UNSET;
+ case android::os::DEST_AUTOMATIC:
+ return true;
+ default:
+ return false;
}
}
-bool
-PrivacySpec::operator<(const PrivacySpec& other) const
-{
- return dest < other.dest;
-}
+bool PrivacySpec::operator<(const PrivacySpec& other) const { return dest < other.dest; }
-bool
-PrivacySpec::CheckPremission(const Privacy* privacy, const uint8_t defaultDest) const
-{
+bool PrivacySpec::CheckPremission(const Privacy* privacy, const uint8_t defaultDest) const {
uint8_t policy = privacy != NULL ? privacy->dest : defaultDest;
return allowDest(dest, policy);
}
-bool
-PrivacySpec::RequireAll() const { return dest == android::os::DEST_LOCAL; }
+bool PrivacySpec::RequireAll() const { return dest == android::os::DEST_LOCAL; }
-PrivacySpec PrivacySpec::new_spec(int dest)
-{
+PrivacySpec PrivacySpec::new_spec(int dest) {
switch (dest) {
case android::os::DEST_AUTOMATIC:
case android::os::DEST_EXPLICIT:
case android::os::DEST_LOCAL:
return PrivacySpec(dest);
default:
- return PrivacySpec();
+ return PrivacySpec(android::os::DEST_AUTOMATIC);
}
}
-
-PrivacySpec PrivacySpec::get_default_dropbox_spec()
-{
- return PrivacySpec(android::os::DEST_AUTOMATIC);
-}
diff --git a/cmds/incidentd/src/Privacy.h b/cmds/incidentd/src/Privacy.h
index 4f3db678f765..6b6de9cd9823 100644
--- a/cmds/incidentd/src/Privacy.h
+++ b/cmds/incidentd/src/Privacy.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#ifndef PRIVACY_H
#define PRIVACY_H
@@ -20,7 +21,7 @@
#include <stdint.h>
// This is the default value of DEST enum, sync with privacy.proto
-const uint8_t DEST_UNSET = 255; // DEST_UNSET is not exposed to libincident
+const uint8_t DEST_UNSET = 255; // DEST_UNSET is not exposed to libincident
const uint8_t DEST_DEFAULT_VALUE = DEST_UNSET;
/*
@@ -68,16 +69,17 @@ public:
bool operator<(const PrivacySpec& other) const;
// check permission of a policy, if returns true, don't strip the data.
- bool CheckPremission(const Privacy* privacy, const uint8_t defaultDest = DEST_DEFAULT_VALUE) const;
+ bool CheckPremission(const Privacy* privacy,
+ const uint8_t defaultDest = DEST_DEFAULT_VALUE) const;
// if returns true, no data need to be stripped.
bool RequireAll() const;
// Constructs spec using static methods below.
static PrivacySpec new_spec(int dest);
- static PrivacySpec get_default_dropbox_spec();
+
private:
PrivacySpec(uint8_t dest) : dest(dest) {}
};
-#endif // PRIVACY_H
+#endif // PRIVACY_H
diff --git a/cmds/incidentd/src/PrivacyBuffer.cpp b/cmds/incidentd/src/PrivacyBuffer.cpp
index f53befefab93..e4128f4217d1 100644
--- a/cmds/incidentd/src/PrivacyBuffer.cpp
+++ b/cmds/incidentd/src/PrivacyBuffer.cpp
@@ -13,29 +13,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "PrivacyBuffer.h"
-#include "io_util.h"
+#include "incidentd_util.h"
+#include <android-base/file.h>
#include <android/util/protobuf.h>
#include <cutils/log.h>
using namespace android::util;
-const bool DEBUG = false;
-
/**
* Write the field to buf based on the wire type, iterator will point to next field.
* If skip is set to true, no data will be written to buf. Return number of bytes written.
*/
-void
-PrivacyBuffer::writeFieldOrSkip(uint32_t fieldTag, bool skip)
-{
- if (DEBUG) ALOGD("%s field %d (wiretype = %d)", skip ? "skip" : "write",
- read_field_id(fieldTag), read_wire_type(fieldTag));
-
+void PrivacyBuffer::writeFieldOrSkip(uint32_t fieldTag, bool skip) {
uint8_t wireType = read_wire_type(fieldTag);
size_t bytesToWrite = 0;
uint32_t varint = 0;
@@ -54,18 +47,17 @@ PrivacyBuffer::writeFieldOrSkip(uint32_t fieldTag, bool skip)
break;
case WIRE_TYPE_LENGTH_DELIMITED:
bytesToWrite = mData.readRawVarint();
- if(!skip) mProto.writeLengthDelimitedHeader(read_field_id(fieldTag), bytesToWrite);
+ if (!skip) mProto.writeLengthDelimitedHeader(read_field_id(fieldTag), bytesToWrite);
break;
case WIRE_TYPE_FIXED32:
if (!skip) mProto.writeRawVarint(fieldTag);
bytesToWrite = 4;
break;
}
- if (DEBUG) ALOGD("%s %d bytes of data", skip ? "skip" : "write", (int)bytesToWrite);
if (skip) {
mData.rp()->move(bytesToWrite);
} else {
- for (size_t i=0; i<bytesToWrite; i++) {
+ for (size_t i = 0; i < bytesToWrite; i++) {
mProto.writeRawByte(mData.next());
}
}
@@ -78,28 +70,29 @@ PrivacyBuffer::writeFieldOrSkip(uint32_t fieldTag, bool skip)
* The iterator must point to the head of a protobuf formatted field for successful operation.
* After exit with NO_ERROR, iterator points to the next protobuf field's head.
*/
-status_t
-PrivacyBuffer::stripField(const Privacy* parentPolicy, const PrivacySpec& spec)
-{
+status_t PrivacyBuffer::stripField(const Privacy* parentPolicy, const PrivacySpec& spec,
+ int depth /* use as a counter for this recusive method. */) {
if (!mData.hasNext() || parentPolicy == NULL) return BAD_VALUE;
uint32_t fieldTag = mData.readRawVarint();
- const Privacy* policy = lookup(parentPolicy, read_field_id(fieldTag));
+ uint32_t fieldId = read_field_id(fieldTag);
+ const Privacy* policy = lookup(parentPolicy, fieldId);
+ VLOG("[Depth %2d]Try to strip id %d, wiretype %d", depth, fieldId, read_wire_type(fieldTag));
if (policy == NULL || policy->children == NULL) {
- if (DEBUG) ALOGD("Not a message field %d: dest(%d)", read_field_id(fieldTag),
- policy != NULL ? policy->dest : parentPolicy->dest);
-
bool skip = !spec.CheckPremission(policy, parentPolicy->dest);
// iterator will point to head of next field
+ size_t currentAt = mData.rp()->pos();
writeFieldOrSkip(fieldTag, skip);
+ VLOG("[Depth %2d]Field %d %ss %d bytes", depth, fieldId, skip ? "skip" : "write",
+ (int)(get_varint_size(fieldTag) + mData.rp()->pos() - currentAt));
return NO_ERROR;
}
// current field is message type and its sub-fields have extra privacy policies
uint32_t msgSize = mData.readRawVarint();
- EncodedBuffer::Pointer start = mData.rp()->copy();
+ size_t start = mData.rp()->pos();
long long token = mProto.start(encode_field_id(policy));
- while (mData.rp()->pos() - start.pos() != msgSize) {
- status_t err = stripField(policy, spec);
+ while (mData.rp()->pos() - start != msgSize) {
+ status_t err = stripField(policy, spec, depth + 1);
if (err != NO_ERROR) return err;
}
mProto.end(token);
@@ -108,53 +101,39 @@ PrivacyBuffer::stripField(const Privacy* parentPolicy, const PrivacySpec& spec)
// ================================================================================
PrivacyBuffer::PrivacyBuffer(const Privacy* policy, EncodedBuffer::iterator& data)
- :mPolicy(policy),
- mData(data),
- mProto(),
- mSize(0)
-{
-}
+ : mPolicy(policy), mData(data), mProto(), mSize(0) {}
-PrivacyBuffer::~PrivacyBuffer()
-{
-}
+PrivacyBuffer::~PrivacyBuffer() {}
-status_t
-PrivacyBuffer::strip(const PrivacySpec& spec)
-{
- if (DEBUG) ALOGD("Strip with spec %d", spec.dest);
+status_t PrivacyBuffer::strip(const PrivacySpec& spec) {
+ VLOG("Strip with spec %d", spec.dest);
// optimization when no strip happens
if (mPolicy == NULL || mPolicy->children == NULL || spec.RequireAll()) {
if (spec.CheckPremission(mPolicy)) mSize = mData.size();
return NO_ERROR;
}
while (mData.hasNext()) {
- status_t err = stripField(mPolicy, spec);
+ status_t err = stripField(mPolicy, spec, 0);
if (err != NO_ERROR) return err;
}
if (mData.bytesRead() != mData.size()) return BAD_VALUE;
mSize = mProto.size();
- mData.rp()->rewind(); // rewind the read pointer back to beginning after the strip.
+ mData.rp()->rewind(); // rewind the read pointer back to beginning after the strip.
return NO_ERROR;
}
-void
-PrivacyBuffer::clear()
-{
+void PrivacyBuffer::clear() {
mSize = 0;
mProto.clear();
}
-size_t
-PrivacyBuffer::size() const { return mSize; }
+size_t PrivacyBuffer::size() const { return mSize; }
-status_t
-PrivacyBuffer::flush(int fd)
-{
+status_t PrivacyBuffer::flush(int fd) {
status_t err = NO_ERROR;
EncodedBuffer::iterator iter = size() == mData.size() ? mData : mProto.data();
while (iter.readBuffer() != NULL) {
- err = write_all(fd, iter.readBuffer(), iter.currentToRead());
+ err = WriteFully(fd, iter.readBuffer(), iter.currentToRead()) ? NO_ERROR : -errno;
iter.rp()->move(iter.currentToRead());
if (err != NO_ERROR) return err;
}
diff --git a/cmds/incidentd/src/PrivacyBuffer.h b/cmds/incidentd/src/PrivacyBuffer.h
index c9ca9a752c9c..92e1a2572465 100644
--- a/cmds/incidentd/src/PrivacyBuffer.h
+++ b/cmds/incidentd/src/PrivacyBuffer.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#ifndef PRIVACY_BUFFER_H
#define PRIVACY_BUFFER_H
@@ -31,14 +32,14 @@ using namespace android::util;
* PrivacyBuffer holds the original protobuf data and strips PII-sensitive fields
* based on the request and holds stripped data in its own buffer for output.
*/
-class PrivacyBuffer
-{
+class PrivacyBuffer {
public:
PrivacyBuffer(const Privacy* policy, EncodedBuffer::iterator& data);
~PrivacyBuffer();
/**
- * Strip based on the request and hold data in its own buffer. Return NO_ERROR if strip succeeds.
+ * Strip based on the request and hold data in its own buffer. Return NO_ERROR if strip
+ * succeeds.
*/
status_t strip(const PrivacySpec& spec);
@@ -64,8 +65,8 @@ private:
ProtoOutputStream mProto;
size_t mSize;
- status_t stripField(const Privacy* parentPolicy, const PrivacySpec& spec);
+ status_t stripField(const Privacy* parentPolicy, const PrivacySpec& spec, int depth);
void writeFieldOrSkip(uint32_t fieldTag, bool skip);
};
-#endif // PRIVACY_BUFFER_H \ No newline at end of file
+#endif // PRIVACY_BUFFER_H \ No newline at end of file
diff --git a/cmds/incidentd/src/Reporter.cpp b/cmds/incidentd/src/Reporter.cpp
index b9f479bd683f..c0b53586a8ce 100644
--- a/cmds/incidentd/src/Reporter.cpp
+++ b/cmds/incidentd/src/Reporter.cpp
@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "Reporter.h"
+#include "Privacy.h"
#include "report_directory.h"
#include "section_list.h"
@@ -25,11 +25,11 @@
#include <private/android_filesystem_config.h>
#include <utils/SystemClock.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <dirent.h>
-#include <fcntl.h>
#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
/**
* The directory where the incident reports are stored.
@@ -38,72 +38,67 @@ static const char* INCIDENT_DIRECTORY = "/data/misc/incidents/";
// ================================================================================
ReportRequest::ReportRequest(const IncidentReportArgs& a,
- const sp<IIncidentReportStatusListener> &l, int f)
- :args(a),
- listener(l),
- fd(f),
- err(NO_ERROR)
-{
-}
+ const sp<IIncidentReportStatusListener>& l, int f)
+ : args(a), listener(l), fd(f), err(NO_ERROR) {}
-ReportRequest::~ReportRequest()
-{
+ReportRequest::~ReportRequest() {
if (fd >= 0) {
// clean up the opened file descriptor
close(fd);
}
}
-bool
-ReportRequest::ok()
-{
- return fd >= 0 && err == NO_ERROR;
-}
+bool ReportRequest::ok() { return fd >= 0 && err == NO_ERROR; }
// ================================================================================
ReportRequestSet::ReportRequestSet()
- :mRequests(),
- mSections(),
- mMainFd(-1),
- mMainDest(-1)
-{
-}
+ : mRequests(), mSections(), mMainFd(-1), mMainDest(-1), mMetadata(), mSectionStats() {}
-ReportRequestSet::~ReportRequestSet()
-{
-}
+ReportRequestSet::~ReportRequestSet() {}
// TODO: dedup on exact same args and fd, report the status back to listener!
-void
-ReportRequestSet::add(const sp<ReportRequest>& request)
-{
+void ReportRequestSet::add(const sp<ReportRequest>& request) {
mRequests.push_back(request);
mSections.merge(request->args);
+ mMetadata.set_request_size(mMetadata.request_size() + 1);
}
-void
-ReportRequestSet::setMainFd(int fd)
-{
+void ReportRequestSet::setMainFd(int fd) {
mMainFd = fd;
+ mMetadata.set_use_dropbox(fd > 0);
}
-void
-ReportRequestSet::setMainDest(int dest)
-{
+void ReportRequestSet::setMainDest(int dest) {
mMainDest = dest;
+ PrivacySpec spec = PrivacySpec::new_spec(dest);
+ switch (spec.dest) {
+ case android::os::DEST_AUTOMATIC:
+ mMetadata.set_dest(IncidentMetadata_Destination_AUTOMATIC);
+ break;
+ case android::os::DEST_EXPLICIT:
+ mMetadata.set_dest(IncidentMetadata_Destination_EXPLICIT);
+ break;
+ case android::os::DEST_LOCAL:
+ mMetadata.set_dest(IncidentMetadata_Destination_LOCAL);
+ break;
+ }
}
-bool
-ReportRequestSet::containsSection(int id) {
- return mSections.containsSection(id);
+bool ReportRequestSet::containsSection(int id) { return mSections.containsSection(id); }
+
+IncidentMetadata::SectionStats* ReportRequestSet::sectionStats(int id) {
+ if (mSectionStats.find(id) == mSectionStats.end()) {
+ auto stats = mMetadata.add_sections();
+ stats->set_id(id);
+ mSectionStats[id] = stats;
+ }
+ return mSectionStats[id];
}
// ================================================================================
Reporter::Reporter() : Reporter(INCIDENT_DIRECTORY) { isTest = false; };
-Reporter::Reporter(const char* directory)
- :batch()
-{
+Reporter::Reporter(const char* directory) : batch() {
char buf[100];
// TODO: Make the max size smaller for user builds.
@@ -121,22 +116,18 @@ Reporter::Reporter(const char* directory)
mFilename = mIncidentDirectory + buf;
}
-Reporter::~Reporter()
-{
-}
-
-Reporter::run_report_status_t
-Reporter::runReport()
-{
+Reporter::~Reporter() {}
+Reporter::run_report_status_t Reporter::runReport() {
status_t err = NO_ERROR;
bool needMainFd = false;
int mainFd = -1;
int mainDest = -1;
HeaderSection headers;
+ MetadataSection metadataSection;
// See if we need the main file
- for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+ for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
if ((*it)->fd < 0 && mainFd < 0) {
needMainFd = true;
mainDest = (*it)->args.dest();
@@ -167,7 +158,7 @@ Reporter::runReport()
}
// Tell everyone that we're starting.
- for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+ for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
if ((*it)->listener != NULL) {
(*it)->listener->onReportStarted();
}
@@ -178,31 +169,36 @@ Reporter::runReport()
// For each of the report fields, see if we need it, and if so, execute the command
// and report to those that care that we're doing it.
- for (const Section** section=SECTION_LIST; *section; section++) {
+ for (const Section** section = SECTION_LIST; *section; section++) {
const int id = (*section)->id;
if (this->batch.containsSection(id)) {
ALOGD("Taking incident report section %d '%s'", id, (*section)->name.string());
- // Notify listener of starting
- for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+ for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
if ((*it)->listener != NULL && (*it)->args.containsSection(id)) {
- (*it)->listener->onReportSectionStatus(id,
- IIncidentReportStatusListener::STATUS_STARTING);
+ (*it)->listener->onReportSectionStatus(
+ id, IIncidentReportStatusListener::STATUS_STARTING);
}
}
// Execute - go get the data and write it into the file descriptors.
+ auto stats = batch.sectionStats(id);
+ int64_t startTime = uptimeMillis();
err = (*section)->Execute(&batch);
+ int64_t endTime = uptimeMillis();
+
+ stats->set_success(err == NO_ERROR);
+ stats->set_exec_duration_ms(endTime - startTime);
if (err != NO_ERROR) {
ALOGW("Incident section %s (%d) failed: %s. Stopping report.",
- (*section)->name.string(), id, strerror(-err));
+ (*section)->name.string(), id, strerror(-err));
goto DONE;
}
// Notify listener of starting
- for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+ for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
if ((*it)->listener != NULL && (*it)->args.containsSection(id)) {
- (*it)->listener->onReportSectionStatus(id,
- IIncidentReportStatusListener::STATUS_FINISHED);
+ (*it)->listener->onReportSectionStatus(
+ id, IIncidentReportStatusListener::STATUS_FINISHED);
}
}
ALOGD("Finish incident report section %d '%s'", id, (*section)->name.string());
@@ -210,13 +206,16 @@ Reporter::runReport()
}
DONE:
+ // Reports the metdadata when taking the incident report.
+ if (!isTest) metadataSection.Execute(&batch);
+
// Close the file.
if (mainFd >= 0) {
close(mainFd);
}
// Tell everyone that we're done.
- for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+ for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
if ((*it)->listener != NULL) {
if (err == NO_ERROR) {
(*it)->listener->onReportFinished();
@@ -238,7 +237,7 @@ DONE:
// If the status was ok, delete the file. If not, leave it around until the next
// boot or the next checkin. If the directory gets too big older files will
// be rotated out.
- if(!isTest) unlink(mFilename.c_str());
+ if (!isTest) unlink(mFilename.c_str());
}
return REPORT_FINISHED;
@@ -247,9 +246,7 @@ DONE:
/**
* Create our output file and set the access permissions to -rw-rw----
*/
-status_t
-Reporter::create_file(int* fd)
-{
+status_t Reporter::create_file(int* fd) {
const char* filename = mFilename.c_str();
*fd = open(filename, O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0660);
@@ -271,9 +268,7 @@ Reporter::create_file(int* fd)
return NO_ERROR;
}
-Reporter::run_report_status_t
-Reporter::upload_backlog()
-{
+Reporter::run_report_status_t Reporter::upload_backlog() {
DIR* dir;
struct dirent* entry;
struct stat st;
@@ -324,4 +319,3 @@ Reporter::upload_backlog()
return REPORT_FINISHED;
}
-
diff --git a/cmds/incidentd/src/Reporter.h b/cmds/incidentd/src/Reporter.h
index f30ecf0dd648..0f3f22172452 100644
--- a/cmds/incidentd/src/Reporter.h
+++ b/cmds/incidentd/src/Reporter.h
@@ -13,13 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#ifndef REPORTER_H
#define REPORTER_H
+#include "frameworks/base/libs/incident/proto/android/os/metadata.pb.h"
+
#include <android/os/IIncidentReportStatusListener.h>
#include <android/os/IncidentReportArgs.h>
+#include <map>
#include <string>
#include <vector>
@@ -30,23 +34,21 @@ using namespace android::os;
using namespace std;
// ================================================================================
-struct ReportRequest : public virtual RefBase
-{
+struct ReportRequest : public virtual RefBase {
IncidentReportArgs args;
sp<IIncidentReportStatusListener> listener;
int fd;
status_t err;
- ReportRequest(const IncidentReportArgs& args,
- const sp<IIncidentReportStatusListener> &listener, int fd);
+ ReportRequest(const IncidentReportArgs& args, const sp<IIncidentReportStatusListener>& listener,
+ int fd);
virtual ~ReportRequest();
- bool ok(); // returns true if the request is ok for write.
+ bool ok(); // returns true if the request is ok for write.
};
// ================================================================================
-class ReportRequestSet
-{
+class ReportRequestSet {
public:
ReportRequestSet();
~ReportRequestSet();
@@ -61,28 +63,31 @@ public:
iterator end() { return mRequests.end(); }
int mainFd() { return mMainFd; }
- bool containsSection(int id);
int mainDest() { return mMainDest; }
+ IncidentMetadata& metadata() { return mMetadata; }
+
+ bool containsSection(int id);
+ IncidentMetadata::SectionStats* sectionStats(int id);
+
private:
vector<sp<ReportRequest>> mRequests;
IncidentReportArgs mSections;
int mMainFd;
int mMainDest;
+
+ IncidentMetadata mMetadata;
+ map<int, IncidentMetadata::SectionStats*> mSectionStats;
};
// ================================================================================
-class Reporter : public virtual RefBase
-{
+class Reporter : public virtual RefBase {
public:
- enum run_report_status_t {
- REPORT_FINISHED = 0,
- REPORT_NEEDS_DROPBOX = 1
- };
+ enum run_report_status_t { REPORT_FINISHED = 0, REPORT_NEEDS_DROPBOX = 1 };
ReportRequestSet batch;
- Reporter();
- Reporter(const char* directory);
+ Reporter(); // PROD must use this constructor.
+ Reporter(const char* directory); // For testing purpose only.
virtual ~Reporter();
// Run the report as described in the batch and args parameters.
@@ -100,8 +105,7 @@ private:
status_t create_file(int* fd);
- bool isTest = true; // default to true for testing
+ bool isTest = true; // default to true for testing
};
-
-#endif // REPORTER_H
+#endif // REPORTER_H
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index faeab87f8178..2e4e980278f9 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -13,8 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "Section.h"
@@ -26,42 +25,41 @@
#include <memory>
#include <mutex>
+#include <android-base/file.h>
#include <android/util/protobuf.h>
#include <binder/IServiceManager.h>
#include <log/log_event_list.h>
-#include <log/logprint.h>
#include <log/log_read.h>
+#include <log/logprint.h>
#include <private/android_logger.h>
#include "FdBuffer.h"
-#include "frameworks/base/core/proto/android/util/log.proto.h"
-#include "io_util.h"
#include "Privacy.h"
#include "PrivacyBuffer.h"
-#include "section_list.h"
+#include "frameworks/base/core/proto/android/util/log.proto.h"
+#include "incidentd_util.h"
+using namespace android::base;
using namespace android::util;
using namespace std;
// special section ids
const int FIELD_ID_INCIDENT_HEADER = 1;
+const int FIELD_ID_INCIDENT_METADATA = 2;
// incident section parameters
-const int WAIT_MAX = 5;
+const int WAIT_MAX = 5;
const struct timespec WAIT_INTERVAL_NS = {0, 200 * 1000 * 1000};
const char INCIDENT_HELPER[] = "/system/bin/incident_helper";
-static pid_t
-fork_execute_incident_helper(const int id, const char* name, Fpipe& p2cPipe, Fpipe& c2pPipe)
-{
- const char* ihArgs[] { INCIDENT_HELPER, "-s", String8::format("%d", id).string(), NULL };
+static pid_t fork_execute_incident_helper(const int id, const char* name, Fpipe& p2cPipe,
+ Fpipe& c2pPipe) {
+ const char* ihArgs[]{INCIDENT_HELPER, "-s", String8::format("%d", id).string(), NULL};
// fork used in multithreaded environment, avoid adding unnecessary code in child process
pid_t pid = fork();
if (pid == 0) {
- if (TEMP_FAILURE_RETRY(dup2(p2cPipe.readFd(), STDIN_FILENO)) != 0
- || !p2cPipe.close()
- || TEMP_FAILURE_RETRY(dup2(c2pPipe.writeFd(), STDOUT_FILENO)) != 1
- || !c2pPipe.close()) {
+ if (TEMP_FAILURE_RETRY(dup2(p2cPipe.readFd(), STDIN_FILENO)) != 0 || !p2cPipe.close() ||
+ TEMP_FAILURE_RETRY(dup2(c2pPipe.writeFd(), STDOUT_FILENO)) != 1 || !c2pPipe.close()) {
ALOGW("%s can't setup stdin and stdout for incident helper", name);
_exit(EXIT_FAILURE);
}
@@ -72,7 +70,7 @@ fork_execute_incident_helper(const int id, const char* name, Fpipe& p2cPipe, Fpi
execv(INCIDENT_HELPER, const_cast<char**>(ihArgs));
ALOGW("%s failed in incident helper process: %s", name, strerror(errno));
- _exit(EXIT_FAILURE); // always exits with failure if any
+ _exit(EXIT_FAILURE); // always exits with failure if any
}
// close the fds used in incident helper
close(p2cPipe.readFd());
@@ -83,18 +81,18 @@ fork_execute_incident_helper(const int id, const char* name, Fpipe& p2cPipe, Fpi
// ================================================================================
static status_t statusCode(int status) {
if (WIFSIGNALED(status)) {
- ALOGD("return by signal: %s", strerror(WTERMSIG(status)));
- return -WTERMSIG(status);
+ VLOG("return by signal: %s", strerror(WTERMSIG(status)));
+ return -WTERMSIG(status);
} else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) {
- ALOGD("return by exit: %s", strerror(WEXITSTATUS(status)));
- return -WEXITSTATUS(status);
+ VLOG("return by exit: %s", strerror(WEXITSTATUS(status)));
+ return -WEXITSTATUS(status);
}
return NO_ERROR;
}
static status_t kill_child(pid_t pid) {
int status;
- ALOGD("try to kill child process %d", pid);
+ VLOG("try to kill child process %d", pid);
kill(pid, SIGKILL);
if (waitpid(pid, &status, 0) == -1) return -1;
return statusCode(status);
@@ -104,7 +102,7 @@ static status_t wait_child(pid_t pid) {
int status;
bool died = false;
// wait for child to report status up to 1 seconds
- for(int loop = 0; !died && loop < WAIT_MAX; loop++) {
+ for (int loop = 0; !died && loop < WAIT_MAX; loop++) {
if (waitpid(pid, &status, WNOHANG) == pid) died = true;
// sleep for 0.2 second
nanosleep(&WAIT_INTERVAL_NS, NULL);
@@ -113,42 +111,24 @@ static status_t wait_child(pid_t pid) {
return statusCode(status);
}
// ================================================================================
-static const Privacy*
-get_privacy_of_section(int id)
-{
- int l = 0;
- int r = PRIVACY_POLICY_COUNT - 1;
- while (l <= r) {
- int mid = (l + r) >> 1;
- const Privacy* p = PRIVACY_POLICY_LIST[mid];
-
- if (p->field_id < (uint32_t)id) {
- l = mid + 1;
- } else if (p->field_id > (uint32_t)id) {
- r = mid - 1;
- } else {
- return p;
- }
- }
- return NULL;
-}
-
-// ================================================================================
-static status_t
-write_section_header(int fd, int sectionId, size_t size)
-{
+static status_t write_section_header(int fd, int sectionId, size_t size) {
uint8_t buf[20];
- uint8_t *p = write_length_delimited_tag_header(buf, sectionId, size);
- return write_all(fd, buf, p-buf);
+ uint8_t* p = write_length_delimited_tag_header(buf, sectionId, size);
+ return WriteFully(fd, buf, p - buf) ? NO_ERROR : -errno;
}
-static status_t
-write_report_requests(const int id, const FdBuffer& buffer, ReportRequestSet* requests)
-{
+static status_t write_report_requests(const int id, const FdBuffer& buffer,
+ ReportRequestSet* requests) {
status_t err = -EBADF;
EncodedBuffer::iterator data = buffer.data();
PrivacyBuffer privacyBuffer(get_privacy_of_section(id), data);
int writeable = 0;
+ auto stats = requests->sectionStats(id);
+
+ stats->set_dump_size_bytes(data.size());
+ stats->set_dump_duration_ms(buffer.durationMs());
+ stats->set_timed_out(buffer.timedOut());
+ stats->set_is_truncated(buffer.truncated());
// The streaming ones, group requests by spec in order to save unnecessary strip operations
map<PrivacySpec, vector<sp<ReportRequest>>> requestsBySpec;
@@ -164,38 +144,49 @@ write_report_requests(const int id, const FdBuffer& buffer, ReportRequestSet* re
for (auto mit = requestsBySpec.begin(); mit != requestsBySpec.end(); mit++) {
PrivacySpec spec = mit->first;
err = privacyBuffer.strip(spec);
- if (err != NO_ERROR) return err; // it means the privacyBuffer data is corrupted.
+ if (err != NO_ERROR) return err; // it means the privacyBuffer data is corrupted.
if (privacyBuffer.size() == 0) continue;
for (auto it = mit->second.begin(); it != mit->second.end(); it++) {
sp<ReportRequest> request = *it;
err = write_section_header(request->fd, id, privacyBuffer.size());
- if (err != NO_ERROR) { request->err = err; continue; }
+ if (err != NO_ERROR) {
+ request->err = err;
+ continue;
+ }
err = privacyBuffer.flush(request->fd);
- if (err != NO_ERROR) { request->err = err; continue; }
+ if (err != NO_ERROR) {
+ request->err = err;
+ continue;
+ }
writeable++;
- ALOGD("Section %d flushed %zu bytes to fd %d with spec %d", id,
- privacyBuffer.size(), request->fd, spec.dest);
+ VLOG("Section %d flushed %zu bytes to fd %d with spec %d", id, privacyBuffer.size(),
+ request->fd, spec.dest);
}
privacyBuffer.clear();
}
// The dropbox file
if (requests->mainFd() >= 0) {
- PrivacySpec spec = requests->mainDest() < 0 ?
- PrivacySpec::get_default_dropbox_spec() :
- PrivacySpec::new_spec(requests->mainDest());
+ PrivacySpec spec = PrivacySpec::new_spec(requests->mainDest());
err = privacyBuffer.strip(spec);
- if (err != NO_ERROR) return err; // the buffer data is corrupted.
+ if (err != NO_ERROR) return err; // the buffer data is corrupted.
if (privacyBuffer.size() == 0) goto DONE;
err = write_section_header(requests->mainFd(), id, privacyBuffer.size());
- if (err != NO_ERROR) { requests->setMainFd(-1); goto DONE; }
+ if (err != NO_ERROR) {
+ requests->setMainFd(-1);
+ goto DONE;
+ }
err = privacyBuffer.flush(requests->mainFd());
- if (err != NO_ERROR) { requests->setMainFd(-1); goto DONE; }
+ if (err != NO_ERROR) {
+ requests->setMainFd(-1);
+ goto DONE;
+ }
writeable++;
- ALOGD("Section %d flushed %zu bytes to dropbox %d with spec %d", id,
- privacyBuffer.size(), requests->mainFd(), spec.dest);
+ VLOG("Section %d flushed %zu bytes to dropbox %d with spec %d", id, privacyBuffer.size(),
+ requests->mainFd(), spec.dest);
+ stats->set_report_size_bytes(privacyBuffer.size());
}
DONE:
@@ -204,67 +195,78 @@ DONE:
}
// ================================================================================
-Section::Section(int i, const int64_t timeoutMs)
- :id(i),
- timeoutMs(timeoutMs)
-{
-}
+Section::Section(int i, const int64_t timeoutMs) : id(i), timeoutMs(timeoutMs) {}
-Section::~Section()
-{
-}
+Section::~Section() {}
// ================================================================================
-HeaderSection::HeaderSection()
- :Section(FIELD_ID_INCIDENT_HEADER, 0)
-{
-}
+HeaderSection::HeaderSection() : Section(FIELD_ID_INCIDENT_HEADER, 0) {}
-HeaderSection::~HeaderSection()
-{
-}
+HeaderSection::~HeaderSection() {}
-status_t
-HeaderSection::Execute(ReportRequestSet* requests) const
-{
- for (ReportRequestSet::iterator it=requests->begin(); it!=requests->end(); it++) {
+status_t HeaderSection::Execute(ReportRequestSet* requests) const {
+ for (ReportRequestSet::iterator it = requests->begin(); it != requests->end(); it++) {
const sp<ReportRequest> request = *it;
const vector<vector<uint8_t>>& headers = request->args.headers();
- for (vector<vector<uint8_t>>::const_iterator buf=headers.begin(); buf!=headers.end(); buf++) {
+ for (vector<vector<uint8_t>>::const_iterator buf = headers.begin(); buf != headers.end();
+ buf++) {
if (buf->empty()) continue;
// So the idea is only requests with negative fd are written to dropbox file.
int fd = request->fd >= 0 ? request->fd : requests->mainFd();
- write_section_header(fd, FIELD_ID_INCIDENT_HEADER, buf->size());
- write_all(fd, (uint8_t const*)buf->data(), buf->size());
+ write_section_header(fd, id, buf->size());
+ WriteFully(fd, (uint8_t const*)buf->data(), buf->size());
// If there was an error now, there will be an error later and we will remove
// it from the list then.
}
}
return NO_ERROR;
}
+// ================================================================================
+MetadataSection::MetadataSection() : Section(FIELD_ID_INCIDENT_METADATA, 0) {}
+MetadataSection::~MetadataSection() {}
+
+status_t MetadataSection::Execute(ReportRequestSet* requests) const {
+ std::string metadataBuf;
+ requests->metadata().SerializeToString(&metadataBuf);
+ for (ReportRequestSet::iterator it = requests->begin(); it != requests->end(); it++) {
+ const sp<ReportRequest> request = *it;
+ if (metadataBuf.empty() || request->fd < 0 || request->err != NO_ERROR) {
+ continue;
+ }
+ write_section_header(request->fd, id, metadataBuf.size());
+ if (!WriteFully(request->fd, (uint8_t const*)metadataBuf.data(), metadataBuf.size())) {
+ ALOGW("Failed to write metadata to fd %d", request->fd);
+ // we don't fail if we can't write to a single request's fd.
+ }
+ }
+ if (requests->mainFd() >= 0 && !metadataBuf.empty()) {
+ write_section_header(requests->mainFd(), id, metadataBuf.size());
+ if (!WriteFully(requests->mainFd(), (uint8_t const*)metadataBuf.data(), metadataBuf.size())) {
+ ALOGW("Failed to write metadata to dropbox fd %d", requests->mainFd());
+ return -1;
+ }
+ }
+ return NO_ERROR;
+}
// ================================================================================
FileSection::FileSection(int id, const char* filename, const int64_t timeoutMs)
- :Section(id, timeoutMs),
- mFilename(filename)
-{
+ : Section(id, timeoutMs), mFilename(filename) {
name = filename;
mIsSysfs = strncmp(filename, "/sys/", 5) == 0;
}
FileSection::~FileSection() {}
-status_t
-FileSection::Execute(ReportRequestSet* requests) const
-{
+status_t FileSection::Execute(ReportRequestSet* requests) const {
// read from mFilename first, make sure the file is available
// add O_CLOEXEC to make sure it is closed when exec incident helper
int fd = open(mFilename, O_RDONLY | O_CLOEXEC);
if (fd == -1) {
- ALOGW("FileSection '%s' failed to open file", this->name.string());
- return -errno;
+ ALOGW("FileSection '%s' failed to open file", this->name.string());
+ return -errno;
}
FdBuffer buffer;
@@ -284,22 +286,23 @@ FileSection::Execute(ReportRequestSet* requests) const
// parent process
status_t readStatus = buffer.readProcessedDataInStream(fd, p2cPipe.writeFd(), c2pPipe.readFd(),
- this->timeoutMs, mIsSysfs);
+ this->timeoutMs, mIsSysfs);
if (readStatus != NO_ERROR || buffer.timedOut()) {
ALOGW("FileSection '%s' failed to read data from incident helper: %s, timedout: %s",
- this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
+ this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
kill_child(pid);
return readStatus;
}
status_t ihStatus = wait_child(pid);
if (ihStatus != NO_ERROR) {
- ALOGW("FileSection '%s' abnormal child process: %s", this->name.string(), strerror(-ihStatus));
+ ALOGW("FileSection '%s' abnormal child process: %s", this->name.string(),
+ strerror(-ihStatus));
return ihStatus;
}
- ALOGD("FileSection '%s' wrote %zd bytes in %d ms", this->name.string(), buffer.size(),
- (int)buffer.durationMs());
+ VLOG("FileSection '%s' wrote %zd bytes in %d ms", this->name.string(), buffer.size(),
+ (int)buffer.durationMs());
status_t err = write_report_requests(this->id, buffer, requests);
if (err != NO_ERROR) {
ALOGW("FileSection '%s' failed writing: %s", this->name.string(), strerror(-err));
@@ -310,8 +313,7 @@ FileSection::Execute(ReportRequestSet* requests) const
}
// ================================================================================
-struct WorkerThreadData : public virtual RefBase
-{
+struct WorkerThreadData : public virtual RefBase {
const WorkerThreadSection* section;
int fds[2];
@@ -328,31 +330,19 @@ struct WorkerThreadData : public virtual RefBase
};
WorkerThreadData::WorkerThreadData(const WorkerThreadSection* sec)
- :section(sec),
- workerDone(false),
- workerError(NO_ERROR)
-{
+ : section(sec), workerDone(false), workerError(NO_ERROR) {
fds[0] = -1;
fds[1] = -1;
}
-WorkerThreadData::~WorkerThreadData()
-{
-}
+WorkerThreadData::~WorkerThreadData() {}
// ================================================================================
-WorkerThreadSection::WorkerThreadSection(int id)
- :Section(id)
-{
-}
+WorkerThreadSection::WorkerThreadSection(int id) : Section(id) {}
-WorkerThreadSection::~WorkerThreadSection()
-{
-}
+WorkerThreadSection::~WorkerThreadSection() {}
-static void*
-worker_thread_func(void* cookie)
-{
+static void* worker_thread_func(void* cookie) {
WorkerThreadData* data = (WorkerThreadData*)cookie;
status_t err = data->section->BlockingCall(data->writeFd());
@@ -368,9 +358,7 @@ worker_thread_func(void* cookie)
return NULL;
}
-status_t
-WorkerThreadSection::Execute(ReportRequestSet* requests) const
-{
+status_t WorkerThreadSection::Execute(ReportRequestSet* requests) const {
status_t err = NO_ERROR;
pthread_t thread;
pthread_attr_t attr;
@@ -413,7 +401,7 @@ WorkerThreadSection::Execute(ReportRequestSet* requests) const
if (err != NO_ERROR) {
// TODO: Log this error into the incident report.
ALOGW("WorkerThreadSection '%s' reader failed with error '%s'", this->name.string(),
- strerror(-err));
+ strerror(-err));
}
// Done with the read fd. The worker thread closes the write one so
@@ -432,7 +420,7 @@ WorkerThreadSection::Execute(ReportRequestSet* requests) const
err = data->workerError;
// TODO: Log this error into the incident report.
ALOGW("WorkerThreadSection '%s' worker failed with error '%s'", this->name.string(),
- strerror(-err));
+ strerror(-err));
}
}
}
@@ -450,13 +438,13 @@ WorkerThreadSection::Execute(ReportRequestSet* requests) const
// just exit with a log messasge.
if (err != NO_ERROR) {
ALOGW("WorkerThreadSection '%s' failed with error '%s'", this->name.string(),
- strerror(-err));
+ strerror(-err));
return NO_ERROR;
}
// Write the data that was collected
- ALOGD("WorkerThreadSection '%s' wrote %zd bytes in %d ms", name.string(), buffer.size(),
- (int)buffer.durationMs());
+ VLOG("WorkerThreadSection '%s' wrote %zd bytes in %d ms", name.string(), buffer.size(),
+ (int)buffer.durationMs());
err = write_report_requests(this->id, buffer, requests);
if (err != NO_ERROR) {
ALOGW("WorkerThreadSection '%s' failed writing: '%s'", this->name.string(), strerror(-err));
@@ -467,14 +455,12 @@ WorkerThreadSection::Execute(ReportRequestSet* requests) const
}
// ================================================================================
-void
-CommandSection::init(const char* command, va_list args)
-{
+void CommandSection::init(const char* command, va_list args) {
va_list copied_args;
int numOfArgs = 0;
va_copy(copied_args, args);
- while(va_arg(copied_args, const char*) != NULL) {
+ while (va_arg(copied_args, const char*) != NULL) {
numOfArgs++;
}
va_end(copied_args);
@@ -484,41 +470,33 @@ CommandSection::init(const char* command, va_list args)
mCommand[0] = command;
name = command;
- for (int i=0; i<numOfArgs; i++) {
+ for (int i = 0; i < numOfArgs; i++) {
const char* arg = va_arg(args, const char*);
- mCommand[i+1] = arg;
+ mCommand[i + 1] = arg;
name += " ";
name += arg;
}
- mCommand[numOfArgs+1] = NULL;
+ mCommand[numOfArgs + 1] = NULL;
}
CommandSection::CommandSection(int id, const int64_t timeoutMs, const char* command, ...)
- :Section(id, timeoutMs)
-{
+ : Section(id, timeoutMs) {
va_list args;
va_start(args, command);
init(command, args);
va_end(args);
}
-CommandSection::CommandSection(int id, const char* command, ...)
- :Section(id)
-{
+CommandSection::CommandSection(int id, const char* command, ...) : Section(id) {
va_list args;
va_start(args, command);
init(command, args);
va_end(args);
}
-CommandSection::~CommandSection()
-{
- free(mCommand);
-}
+CommandSection::~CommandSection() { free(mCommand); }
-status_t
-CommandSection::Execute(ReportRequestSet* requests) const
-{
+status_t CommandSection::Execute(ReportRequestSet* requests) const {
FdBuffer buffer;
Fpipe cmdPipe;
Fpipe ihPipe;
@@ -537,13 +515,15 @@ CommandSection::Execute(ReportRequestSet* requests) const
if (cmdPid == 0) {
// replace command's stdout with ihPipe's write Fd
if (dup2(cmdPipe.writeFd(), STDOUT_FILENO) != 1 || !ihPipe.close() || !cmdPipe.close()) {
- ALOGW("CommandSection '%s' failed to set up stdout: %s", this->name.string(), strerror(errno));
+ ALOGW("CommandSection '%s' failed to set up stdout: %s", this->name.string(),
+ strerror(errno));
_exit(EXIT_FAILURE);
}
- execvp(this->mCommand[0], (char *const *) this->mCommand);
- int err = errno; // record command error code
- ALOGW("CommandSection '%s' failed in executing command: %s", this->name.string(), strerror(errno));
- _exit(err); // exit with command error code
+ execvp(this->mCommand[0], (char* const*)this->mCommand);
+ int err = errno; // record command error code
+ ALOGW("CommandSection '%s' failed in executing command: %s", this->name.string(),
+ strerror(errno));
+ _exit(err); // exit with command error code
}
pid_t ihPid = fork_execute_incident_helper(this->id, this->name.string(), cmdPipe, ihPipe);
if (ihPid == -1) {
@@ -555,24 +535,26 @@ CommandSection::Execute(ReportRequestSet* requests) const
status_t readStatus = buffer.read(ihPipe.readFd(), this->timeoutMs);
if (readStatus != NO_ERROR || buffer.timedOut()) {
ALOGW("CommandSection '%s' failed to read data from incident helper: %s, timedout: %s",
- this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
+ this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
kill_child(cmdPid);
kill_child(ihPid);
return readStatus;
}
- // TODO: wait for command here has one trade-off: the failed status of command won't be detected until
+ // TODO: wait for command here has one trade-off: the failed status of command won't be detected
+ // until
// buffer timeout, but it has advatage on starting the data stream earlier.
status_t cmdStatus = wait_child(cmdPid);
- status_t ihStatus = wait_child(ihPid);
+ status_t ihStatus = wait_child(ihPid);
if (cmdStatus != NO_ERROR || ihStatus != NO_ERROR) {
- ALOGW("CommandSection '%s' abnormal child processes, return status: command: %s, incident helper: %s",
- this->name.string(), strerror(-cmdStatus), strerror(-ihStatus));
+ ALOGW("CommandSection '%s' abnormal child processes, return status: command: %s, incident "
+ "helper: %s",
+ this->name.string(), strerror(-cmdStatus), strerror(-ihStatus));
return cmdStatus != NO_ERROR ? cmdStatus : ihStatus;
}
- ALOGD("CommandSection '%s' wrote %zd bytes in %d ms", this->name.string(), buffer.size(),
- (int)buffer.durationMs());
+ VLOG("CommandSection '%s' wrote %zd bytes in %d ms", this->name.string(), buffer.size(),
+ (int)buffer.durationMs());
status_t err = write_report_requests(this->id, buffer, requests);
if (err != NO_ERROR) {
ALOGW("CommandSection '%s' failed writing: %s", this->name.string(), strerror(-err));
@@ -583,9 +565,7 @@ CommandSection::Execute(ReportRequestSet* requests) const
// ================================================================================
DumpsysSection::DumpsysSection(int id, const char* service, ...)
- :WorkerThreadSection(id),
- mService(service)
-{
+ : WorkerThreadSection(id), mService(service) {
name = "dumpsys ";
name += service;
@@ -603,13 +583,9 @@ DumpsysSection::DumpsysSection(int id, const char* service, ...)
va_end(args);
}
-DumpsysSection::~DumpsysSection()
-{
-}
+DumpsysSection::~DumpsysSection() {}
-status_t
-DumpsysSection::BlockingCall(int pipeWriteFd) const
-{
+status_t DumpsysSection::BlockingCall(int pipeWriteFd) const {
// checkService won't wait for the service to show up like getService will.
sp<IBinder> service = defaultServiceManager()->checkService(mService);
@@ -633,30 +609,23 @@ DumpsysSection::BlockingCall(int pipeWriteFd) const
// initialization only once in Section.cpp.
map<log_id_t, log_time> LogSection::gLastLogsRetrieved;
-LogSection::LogSection(int id, log_id_t logID)
- :WorkerThreadSection(id),
- mLogID(logID)
-{
+LogSection::LogSection(int id, log_id_t logID) : WorkerThreadSection(id), mLogID(logID) {
name += "logcat ";
name += android_log_id_to_name(logID);
switch (logID) {
- case LOG_ID_EVENTS:
- case LOG_ID_STATS:
- case LOG_ID_SECURITY:
- mBinary = true;
- break;
- default:
- mBinary = false;
+ case LOG_ID_EVENTS:
+ case LOG_ID_STATS:
+ case LOG_ID_SECURITY:
+ mBinary = true;
+ break;
+ default:
+ mBinary = false;
}
}
-LogSection::~LogSection()
-{
-}
+LogSection::~LogSection() {}
-static size_t
-trimTail(char const* buf, size_t len)
-{
+static size_t trimTail(char const* buf, size_t len) {
while (len > 0) {
char c = buf[len - 1];
if (c == '\0' || c == ' ' || c == '\n' || c == '\r' || c == ':') {
@@ -672,17 +641,15 @@ static inline int32_t get4LE(uint8_t const* src) {
return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
}
-status_t
-LogSection::BlockingCall(int pipeWriteFd) const
-{
+status_t LogSection::BlockingCall(int pipeWriteFd) const {
status_t err = NO_ERROR;
// Open log buffer and getting logs since last retrieved time if any.
unique_ptr<logger_list, void (*)(logger_list*)> loggers(
- gLastLogsRetrieved.find(mLogID) == gLastLogsRetrieved.end() ?
- android_logger_list_alloc(ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, 0) :
- android_logger_list_alloc_time(ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
- gLastLogsRetrieved[mLogID], 0),
- android_logger_list_free);
+ gLastLogsRetrieved.find(mLogID) == gLastLogsRetrieved.end()
+ ? android_logger_list_alloc(ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, 0)
+ : android_logger_list_alloc_time(ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
+ gLastLogsRetrieved[mLogID], 0),
+ android_logger_list_free);
if (android_logger_open(loggers.get(), mLogID) == NULL) {
ALOGW("LogSection %s: Can't get logger.", this->name.string());
@@ -693,7 +660,7 @@ LogSection::BlockingCall(int pipeWriteFd) const
log_time lastTimestamp(0);
ProtoOutputStream proto;
- while (true) { // keeps reading until logd buffer is fully read.
+ while (true) { // keeps reading until logd buffer is fully read.
status_t err = android_logger_list_read(loggers.get(), &msg);
// err = 0 - no content, unexpected connection drop or EOF.
// err = +ive number - size of retrieved data from logger
@@ -708,7 +675,8 @@ LogSection::BlockingCall(int pipeWriteFd) const
if (mBinary) {
// remove the first uint32 which is tag's index in event log tags
android_log_context context = create_android_log_parser(msg.msg() + sizeof(uint32_t),
- msg.len() - sizeof(uint32_t));;
+ msg.len() - sizeof(uint32_t));
+ ;
android_log_list_element elem;
lastTimestamp.tv_sec = msg.entry_v1.sec;
@@ -718,38 +686,46 @@ LogSection::BlockingCall(int pipeWriteFd) const
long long token = proto.start(LogProto::BINARY_LOGS);
proto.write(BinaryLogEntry::SEC, msg.entry_v1.sec);
proto.write(BinaryLogEntry::NANOSEC, msg.entry_v1.nsec);
- proto.write(BinaryLogEntry::UID, (int) msg.entry_v4.uid);
+ proto.write(BinaryLogEntry::UID, (int)msg.entry_v4.uid);
proto.write(BinaryLogEntry::PID, msg.entry_v1.pid);
proto.write(BinaryLogEntry::TID, msg.entry_v1.tid);
- proto.write(BinaryLogEntry::TAG_INDEX, get4LE(reinterpret_cast<uint8_t const*>(msg.msg())));
+ proto.write(BinaryLogEntry::TAG_INDEX,
+ get4LE(reinterpret_cast<uint8_t const*>(msg.msg())));
do {
elem = android_log_read_next(context);
long long elemToken = proto.start(BinaryLogEntry::ELEMS);
switch (elem.type) {
case EVENT_TYPE_INT:
- proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_INT);
- proto.write(BinaryLogEntry::Elem::VAL_INT32, (int) elem.data.int32);
+ proto.write(BinaryLogEntry::Elem::TYPE,
+ BinaryLogEntry::Elem::EVENT_TYPE_INT);
+ proto.write(BinaryLogEntry::Elem::VAL_INT32, (int)elem.data.int32);
break;
case EVENT_TYPE_LONG:
- proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_LONG);
- proto.write(BinaryLogEntry::Elem::VAL_INT64, (long long) elem.data.int64);
+ proto.write(BinaryLogEntry::Elem::TYPE,
+ BinaryLogEntry::Elem::EVENT_TYPE_LONG);
+ proto.write(BinaryLogEntry::Elem::VAL_INT64, (long long)elem.data.int64);
break;
case EVENT_TYPE_STRING:
- proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_STRING);
+ proto.write(BinaryLogEntry::Elem::TYPE,
+ BinaryLogEntry::Elem::EVENT_TYPE_STRING);
proto.write(BinaryLogEntry::Elem::VAL_STRING, elem.data.string, elem.len);
break;
case EVENT_TYPE_FLOAT:
- proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_FLOAT);
+ proto.write(BinaryLogEntry::Elem::TYPE,
+ BinaryLogEntry::Elem::EVENT_TYPE_FLOAT);
proto.write(BinaryLogEntry::Elem::VAL_FLOAT, elem.data.float32);
break;
case EVENT_TYPE_LIST:
- proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_LIST);
+ proto.write(BinaryLogEntry::Elem::TYPE,
+ BinaryLogEntry::Elem::EVENT_TYPE_LIST);
break;
case EVENT_TYPE_LIST_STOP:
- proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_LIST_STOP);
+ proto.write(BinaryLogEntry::Elem::TYPE,
+ BinaryLogEntry::Elem::EVENT_TYPE_LIST_STOP);
break;
case EVENT_TYPE_UNKNOWN:
- proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_UNKNOWN);
+ proto.write(BinaryLogEntry::Elem::TYPE,
+ BinaryLogEntry::Elem::EVENT_TYPE_UNKNOWN);
break;
}
proto.end(elemToken);
@@ -777,7 +753,8 @@ LogSection::BlockingCall(int pipeWriteFd) const
proto.write(TextLogEntry::PID, entry.pid);
proto.write(TextLogEntry::TID, entry.tid);
proto.write(TextLogEntry::TAG, entry.tag, trimTail(entry.tag, entry.tagLen));
- proto.write(TextLogEntry::LOG, entry.message, trimTail(entry.message, entry.messageLen));
+ proto.write(TextLogEntry::LOG, entry.message,
+ trimTail(entry.message, entry.messageLen));
proto.end(token);
}
}
diff --git a/cmds/incidentd/src/Section.h b/cmds/incidentd/src/Section.h
index d440ee92601c..d6446810c40f 100644
--- a/cmds/incidentd/src/Section.h
+++ b/cmds/incidentd/src/Section.h
@@ -13,31 +13,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#ifndef SECTIONS_H
#define SECTIONS_H
#include "Reporter.h"
-#include <map>
#include <stdarg.h>
+#include <map>
-#include <utils/String8.h>
#include <utils/String16.h>
+#include <utils/String8.h>
#include <utils/Vector.h>
using namespace android;
-const int64_t REMOTE_CALL_TIMEOUT_MS = 10 * 1000; // 10 seconds
+const int64_t REMOTE_CALL_TIMEOUT_MS = 10 * 1000; // 10 seconds
/**
* Base class for sections
*/
-class Section
-{
+class Section {
public:
const int id;
- const int64_t timeoutMs; // each section must have a timeout
+ const int64_t timeoutMs; // each section must have a timeout
String8 name;
Section(int id, const int64_t timeoutMs = REMOTE_CALL_TIMEOUT_MS);
@@ -49,8 +49,7 @@ public:
/**
* Section that generates incident headers.
*/
-class HeaderSection : public Section
-{
+class HeaderSection : public Section {
public:
HeaderSection();
virtual ~HeaderSection();
@@ -59,10 +58,20 @@ public:
};
/**
+ * Section that generates incident metadata.
+ */
+class MetadataSection : public Section {
+public:
+ MetadataSection();
+ virtual ~MetadataSection();
+
+ virtual status_t Execute(ReportRequestSet* requests) const;
+};
+
+/**
* Section that reads in a file.
*/
-class FileSection : public Section
-{
+class FileSection : public Section {
public:
FileSection(int id, const char* filename, const int64_t timeoutMs = 5000 /* 5 seconds */);
virtual ~FileSection();
@@ -71,14 +80,13 @@ public:
private:
const char* mFilename;
- bool mIsSysfs; // sysfs files are pollable but return POLLERR by default, handle it separately
+ bool mIsSysfs; // sysfs files are pollable but return POLLERR by default, handle it separately
};
/**
* Base class for sections that call a command that might need a timeout.
*/
-class WorkerThreadSection : public Section
-{
+class WorkerThreadSection : public Section {
public:
WorkerThreadSection(int id);
virtual ~WorkerThreadSection();
@@ -91,8 +99,7 @@ public:
/**
* Section that forks and execs a command, and puts stdout as the section.
*/
-class CommandSection : public Section
-{
+class CommandSection : public Section {
public:
CommandSection(int id, const int64_t timeoutMs, const char* command, ...);
@@ -111,8 +118,7 @@ private:
/**
* Section that calls dumpsys on a system service.
*/
-class DumpsysSection : public WorkerThreadSection
-{
+class DumpsysSection : public WorkerThreadSection {
public:
DumpsysSection(int id, const char* service, ...);
virtual ~DumpsysSection();
@@ -127,8 +133,7 @@ private:
/**
* Section that reads from logd.
*/
-class LogSection : public WorkerThreadSection
-{
+class LogSection : public WorkerThreadSection {
// global last log retrieved timestamp for each log_id_t.
static map<log_id_t, log_time> gLastLogsRetrieved;
@@ -143,5 +148,4 @@ private:
bool mBinary;
};
-#endif // SECTIONS_H
-
+#endif // SECTIONS_H
diff --git a/cmds/incidentd/src/incidentd_util.cpp b/cmds/incidentd/src/incidentd_util.cpp
new file mode 100644
index 000000000000..2415860572fb
--- /dev/null
+++ b/cmds/incidentd/src/incidentd_util.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+#include "incidentd_util.h"
+
+#include "section_list.h"
+
+const Privacy* get_privacy_of_section(int id) {
+ int l = 0;
+ int r = PRIVACY_POLICY_COUNT - 1;
+ while (l <= r) {
+ int mid = (l + r) >> 1;
+ const Privacy* p = PRIVACY_POLICY_LIST[mid];
+
+ if (p->field_id < (uint32_t)id) {
+ l = mid + 1;
+ } else if (p->field_id > (uint32_t)id) {
+ r = mid - 1;
+ } else {
+ return p;
+ }
+ }
+ return NULL;
+}
+
+// ================================================================================
+Fpipe::Fpipe() : mRead(), mWrite() {}
+
+Fpipe::~Fpipe() { close(); }
+
+bool Fpipe::close() {
+ mRead.reset();
+ mWrite.reset();
+ return true;
+}
+
+bool Fpipe::init() { return Pipe(&mRead, &mWrite); }
+
+int Fpipe::readFd() const { return mRead.get(); }
+
+int Fpipe::writeFd() const { return mWrite.get(); } \ No newline at end of file
diff --git a/cmds/incidentd/src/io_util.h b/cmds/incidentd/src/incidentd_util.h
index 320dd6c386d2..09aa0404277a 100644
--- a/cmds/incidentd/src/io_util.h
+++ b/cmds/incidentd/src/incidentd_util.h
@@ -13,16 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
-#ifndef IO_UTIL_H
-#define IO_UTIL_H
+#ifndef INCIDENTD_UTIL_H
+#define INCIDENTD_UTIL_H
-#include <stdint.h>
-#include <utils/Errors.h>
+#include <android-base/unique_fd.h>
-using namespace android;
+#include "Privacy.h"
-status_t write_all(int fd, uint8_t const* buf, size_t size);
+using namespace android::base;
+
+const Privacy* get_privacy_of_section(int id);
class Fpipe {
public:
@@ -35,7 +37,8 @@ public:
int writeFd() const;
private:
- int mFds[2];
+ unique_fd mRead;
+ unique_fd mWrite;
};
-#endif // IO_UTIL_H \ No newline at end of file
+#endif // INCIDENTD_UTIL_H \ No newline at end of file
diff --git a/cmds/incidentd/src/main.cpp b/cmds/incidentd/src/main.cpp
index 3a7511d43048..38b7449403fe 100644
--- a/cmds/incidentd/src/main.cpp
+++ b/cmds/incidentd/src/main.cpp
@@ -13,8 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "IncidentService.h"
@@ -23,25 +22,22 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <binder/Status.h>
-#include <cutils/log.h>
#include <utils/Looper.h>
#include <utils/StrongPointer.h>
-#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/types.h>
using namespace android;
// ================================================================================
-int
-main(int /*argc*/, char** /*argv*/)
-{
+int main(int /*argc*/, char** /*argv*/) {
// Set up the looper
sp<Looper> looper(Looper::prepare(0 /* opts */));
// Set up the binder
sp<ProcessState> ps(ProcessState::self());
- ps->setThreadPoolMaxThreadCount(1); // everything is oneway, let it queue and save ram
+ ps->setThreadPoolMaxThreadCount(1); // everything is oneway, let it queue and save ram
ps->startThreadPool();
ps->giveThreadPoolName();
IPCThreadState::self()->disableBackgroundScheduling(true);
diff --git a/cmds/incidentd/src/report_directory.cpp b/cmds/incidentd/src/report_directory.cpp
index 20111d8ae89a..b71c066201c4 100644
--- a/cmds/incidentd/src/report_directory.cpp
+++ b/cmds/incidentd/src/report_directory.cpp
@@ -13,19 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "report_directory.h"
-#include <cutils/log.h>
#include <private/android_filesystem_config.h>
#include <utils/String8.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <dirent.h>
#include <libgen.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#include <vector>
@@ -33,9 +31,7 @@
using namespace android;
using namespace std;
-status_t
-create_directory(const char* directory)
-{
+status_t create_directory(const char* directory) {
struct stat st;
status_t err = NO_ERROR;
char* dir = strdup(directory);
@@ -75,14 +71,14 @@ create_directory(const char* directory)
goto done;
}
if ((st.st_mode & 0777) != 0770) {
- ALOGE("No incident reports today. Mode is %0o on report directory %s",
- st.st_mode, directory);
+ ALOGE("No incident reports today. Mode is %0o on report directory %s", st.st_mode,
+ directory);
err = BAD_VALUE;
goto done;
}
if (st.st_uid != AID_INCIDENTD || st.st_gid != AID_INCIDENTD) {
ALOGE("No incident reports today. Owner is %d and group is %d on report directory %s",
- st.st_uid, st.st_gid, directory);
+ st.st_uid, st.st_gid, directory);
err = BAD_VALUE;
goto done;
}
@@ -92,20 +88,17 @@ done:
return err;
}
-static bool
-stat_mtime_cmp(const pair<String8,struct stat>& a, const pair<String8,struct stat>& b)
-{
+static bool stat_mtime_cmp(const pair<String8, struct stat>& a,
+ const pair<String8, struct stat>& b) {
return a.second.st_mtime < b.second.st_mtime;
}
-void
-clean_directory(const char* directory, off_t maxSize, size_t maxCount)
-{
+void clean_directory(const char* directory, off_t maxSize, size_t maxCount) {
DIR* dir;
struct dirent* entry;
struct stat st;
- vector<pair<String8,struct stat>> files;
+ vector<pair<String8, struct stat>> files;
if ((dir = opendir(directory)) == NULL) {
ALOGE("Couldn't open incident directory: %s", directory);
@@ -131,7 +124,7 @@ clean_directory(const char* directory, off_t maxSize, size_t maxCount)
if (!S_ISREG(st.st_mode)) {
continue;
}
- files.push_back(pair<String8,struct stat>(filename, st));
+ files.push_back(pair<String8, struct stat>(filename, st));
totalSize += st.st_size;
totalCount++;
@@ -148,8 +141,8 @@ clean_directory(const char* directory, off_t maxSize, size_t maxCount)
sort(files.begin(), files.end(), stat_mtime_cmp);
// Remove files until we're under our limits.
- for (vector<pair<String8,struct stat>>::iterator it = files.begin();
- it != files.end() && totalSize >= maxSize && totalCount >= maxCount; it++) {
+ for (vector<pair<String8, struct stat>>::iterator it = files.begin();
+ it != files.end() && totalSize >= maxSize && totalCount >= maxCount; it++) {
remove(it->first.string());
totalSize -= it->second.st_size;
totalCount--;
diff --git a/cmds/incidentd/src/report_directory.h b/cmds/incidentd/src/report_directory.h
index bed4f869cfe4..2a3cf4c0f701 100644
--- a/cmds/incidentd/src/report_directory.h
+++ b/cmds/incidentd/src/report_directory.h
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#ifndef DIRECTORY_CLEANER_H
#define DIRECTORY_CLEANER_H
-#include <utils/Errors.h>
-
#include <sys/types.h>
+#include <utils/Errors.h>
-using namespace android;
-
-status_t create_directory(const char* directory);
+android::status_t create_directory(const char* directory);
void clean_directory(const char* directory, off_t maxSize, size_t maxCount);
-#endif // DIRECTORY_CLEANER_H
+#endif // DIRECTORY_CLEANER_H
diff --git a/cmds/incidentd/src/section_list.h b/cmds/incidentd/src/section_list.h
index ddc0505df331..697e66f9cf40 100644
--- a/cmds/incidentd/src/section_list.h
+++ b/cmds/incidentd/src/section_list.h
@@ -13,11 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#ifndef SECTION_LIST_H
#define SECTION_LIST_H
-#include <log/log_event_list.h> // include log_id_t enums.
+#include <log/log_event_list.h> // include log_id_t enums.
#include "Privacy.h"
#include "Section.h"
@@ -36,5 +37,4 @@ extern const Privacy** PRIVACY_POLICY_LIST;
extern const int PRIVACY_POLICY_COUNT;
-#endif // SECTION_LIST_H
-
+#endif // SECTION_LIST_H
diff --git a/cmds/incidentd/tests/FdBuffer_test.cpp b/cmds/incidentd/tests/FdBuffer_test.cpp
index 3fd2ed82a26e..956c8d39346a 100644
--- a/cmds/incidentd/tests/FdBuffer_test.cpp
+++ b/cmds/incidentd/tests/FdBuffer_test.cpp
@@ -11,11 +11,10 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "FdBuffer.h"
-#include "io_util.h"
+#include "incidentd_util.h"
#include <android-base/file.h>
#include <android-base/test_utils.h>
@@ -48,7 +47,7 @@ public:
}
void AssertBufferContent(const char* expected) {
- int i=0;
+ int i = 0;
EncodedBuffer::iterator it = buffer.data();
while (it.hasNext()) {
ASSERT_EQ(it.next(), expected[i++]);
@@ -100,7 +99,7 @@ TEST_F(FdBufferTest, ReadAndIterate) {
ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
- int i=0;
+ int i = 0;
EncodedBuffer::iterator it = buffer.data();
while (it.hasNext()) {
EXPECT_EQ(it.next(), (uint8_t)testdata[i++]);
@@ -118,7 +117,7 @@ TEST_F(FdBufferTest, ReadTimeout) {
if (pid == 0) {
close(c2pPipe.readFd());
- while(true) {
+ while (true) {
write(c2pPipe.writeFd(), "poo", 3);
sleep(1);
}
@@ -130,7 +129,7 @@ TEST_F(FdBufferTest, ReadTimeout) {
ASSERT_EQ(NO_ERROR, status);
EXPECT_TRUE(buffer.timedOut());
- kill(pid, SIGKILL); // reap the child process
+ kill(pid, SIGKILL); // reap the child process
}
}
@@ -155,8 +154,8 @@ TEST_F(FdBufferTest, ReadInStreamAndWrite) {
close(p2cPipe.readFd());
close(c2pPipe.writeFd());
- ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
- p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
+ ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(),
+ c2pPipe.readFd(), READ_TIMEOUT));
AssertBufferReadSuccessful(HEAD.size() + testdata.size());
AssertBufferContent(expected.c_str());
wait(&pid);
@@ -187,8 +186,8 @@ TEST_F(FdBufferTest, ReadInStreamAndWriteAllAtOnce) {
close(p2cPipe.readFd());
close(c2pPipe.writeFd());
- ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
- p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
+ ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(),
+ c2pPipe.readFd(), READ_TIMEOUT));
AssertBufferReadSuccessful(HEAD.size() + testdata.size());
AssertBufferContent(expected.c_str());
wait(&pid);
@@ -212,8 +211,8 @@ TEST_F(FdBufferTest, ReadInStreamEmpty) {
close(p2cPipe.readFd());
close(c2pPipe.writeFd());
- ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
- p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
+ ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(),
+ c2pPipe.readFd(), READ_TIMEOUT));
AssertBufferReadSuccessful(0);
AssertBufferContent("");
wait(&pid);
@@ -222,7 +221,7 @@ TEST_F(FdBufferTest, ReadInStreamEmpty) {
TEST_F(FdBufferTest, ReadInStreamMoreThan4MB) {
const std::string testFile = kTestDataPath + "morethan4MB.txt";
- size_t fourMB = (size_t) 4 * 1024 * 1024;
+ size_t fourMB = (size_t)4 * 1024 * 1024;
int fd = open(testFile.c_str(), O_RDONLY | O_CLOEXEC);
ASSERT_NE(fd, -1);
int pid = fork();
@@ -239,8 +238,8 @@ TEST_F(FdBufferTest, ReadInStreamMoreThan4MB) {
close(p2cPipe.readFd());
close(c2pPipe.writeFd());
- ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(fd,
- p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
+ ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(fd, p2cPipe.writeFd(),
+ c2pPipe.readFd(), READ_TIMEOUT));
EXPECT_EQ(buffer.size(), fourMB);
EXPECT_FALSE(buffer.timedOut());
EXPECT_TRUE(buffer.truncated());
@@ -276,9 +275,9 @@ TEST_F(FdBufferTest, ReadInStreamTimeOut) {
close(p2cPipe.readFd());
close(c2pPipe.writeFd());
- ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
- p2cPipe.writeFd(), c2pPipe.readFd(), QUICK_TIMEOUT_MS));
+ ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(),
+ c2pPipe.readFd(), QUICK_TIMEOUT_MS));
EXPECT_TRUE(buffer.timedOut());
- kill(pid, SIGKILL); // reap the child process
+ kill(pid, SIGKILL); // reap the child process
}
}
diff --git a/cmds/incidentd/tests/PrivacyBuffer_test.cpp b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
index c7bfe5555743..7ea9bbfcd8c7 100644
--- a/cmds/incidentd/tests/PrivacyBuffer_test.cpp
+++ b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
@@ -11,8 +11,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "FdBuffer.h"
#include "PrivacyBuffer.h"
@@ -37,13 +36,12 @@ const uint8_t OTHER_TYPE = 1;
const uint8_t STRING_TYPE = 9;
const uint8_t MESSAGE_TYPE = 11;
const string STRING_FIELD_0 = "\x02\viamtestdata";
-const string VARINT_FIELD_1 = "\x08\x96\x01"; // 150
+const string VARINT_FIELD_1 = "\x08\x96\x01"; // 150
const string STRING_FIELD_2 = "\x12\vwhatthefuck";
-const string FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff"; // -1
-const string FIX32_FIELD_4 = "\x25\xff\xff\xff\xff"; // -1
+const string FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff"; // -1
+const string FIX32_FIELD_4 = "\x25\xff\xff\xff\xff"; // -1
const string MESSAGE_FIELD_5 = "\x2a\x10" + VARINT_FIELD_1 + STRING_FIELD_2;
-
class PrivacyBufferTest : public Test {
public:
virtual ~PrivacyBufferTest() {
@@ -55,9 +53,7 @@ public:
}
}
- virtual void SetUp() override {
- ASSERT_NE(tf.fd, -1);
- }
+ virtual void SetUp() override { ASSERT_NE(tf.fd, -1); }
void writeToFdBuffer(string str) {
ASSERT_TRUE(WriteStringToFile(str, tf.path));
@@ -81,11 +77,11 @@ public:
}
void assertStripByFields(uint8_t dest, string expected, int size, Privacy* privacy, ...) {
- Privacy* list[size+1];
+ Privacy* list[size + 1];
list[0] = privacy;
va_list args;
va_start(args, privacy);
- for (int i=1; i<size; i++) {
+ for (int i = 1; i < size; i++) {
Privacy* p = va_arg(args, Privacy*);
list[i] = p;
}
@@ -115,13 +111,14 @@ public:
}
FdBuffer buffer;
+
private:
TemporaryFile tf;
// Littering this code with unique_ptr (or similar) is ugly, so we just
// mass-free everything after the test completes.
- std::vector<Privacy *> privacies;
+ std::vector<Privacy*> privacies;
- Privacy *new_uninit_privacy() {
+ Privacy* new_uninit_privacy() {
Privacy* p = new Privacy;
privacies.push_back(p);
return p;
@@ -165,63 +162,69 @@ TEST_F(PrivacyBufferTest, StripLengthDelimitedField_Message) {
TEST_F(PrivacyBufferTest, NoStripVarintField) {
writeToFdBuffer(VARINT_FIELD_1);
- assertStripByFields(DEST_EXPLICIT, VARINT_FIELD_1, 1, create_privacy(1, OTHER_TYPE, DEST_AUTOMATIC));
+ assertStripByFields(DEST_EXPLICIT, VARINT_FIELD_1, 1,
+ create_privacy(1, OTHER_TYPE, DEST_AUTOMATIC));
}
TEST_F(PrivacyBufferTest, NoStripLengthDelimitedField_String) {
writeToFdBuffer(STRING_FIELD_2);
- assertStripByFields(DEST_EXPLICIT, STRING_FIELD_2, 1, create_privacy(2, STRING_TYPE, DEST_AUTOMATIC));
+ assertStripByFields(DEST_EXPLICIT, STRING_FIELD_2, 1,
+ create_privacy(2, STRING_TYPE, DEST_AUTOMATIC));
}
TEST_F(PrivacyBufferTest, NoStripFixed64Field) {
writeToFdBuffer(FIX64_FIELD_3);
- assertStripByFields(DEST_EXPLICIT, FIX64_FIELD_3, 1, create_privacy(3, OTHER_TYPE, DEST_AUTOMATIC));
+ assertStripByFields(DEST_EXPLICIT, FIX64_FIELD_3, 1,
+ create_privacy(3, OTHER_TYPE, DEST_AUTOMATIC));
}
TEST_F(PrivacyBufferTest, NoStripFixed32Field) {
writeToFdBuffer(FIX32_FIELD_4);
- assertStripByFields(DEST_EXPLICIT, FIX32_FIELD_4, 1, create_privacy(4, OTHER_TYPE, DEST_AUTOMATIC));
+ assertStripByFields(DEST_EXPLICIT, FIX32_FIELD_4, 1,
+ create_privacy(4, OTHER_TYPE, DEST_AUTOMATIC));
}
TEST_F(PrivacyBufferTest, NoStripLengthDelimitedField_Message) {
writeToFdBuffer(MESSAGE_FIELD_5);
- assertStripByFields(DEST_EXPLICIT, MESSAGE_FIELD_5, 1, create_privacy(5, MESSAGE_TYPE, DEST_AUTOMATIC));
+ assertStripByFields(DEST_EXPLICIT, MESSAGE_FIELD_5, 1,
+ create_privacy(5, MESSAGE_TYPE, DEST_AUTOMATIC));
}
TEST_F(PrivacyBufferTest, StripVarintAndString) {
- writeToFdBuffer(STRING_FIELD_0 + VARINT_FIELD_1 + STRING_FIELD_2
- + FIX64_FIELD_3 + FIX32_FIELD_4);
+ writeToFdBuffer(STRING_FIELD_0 + VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3 +
+ FIX32_FIELD_4);
string expected = STRING_FIELD_0 + FIX64_FIELD_3 + FIX32_FIELD_4;
- assertStripByFields(DEST_EXPLICIT, expected, 2,
- create_privacy(1, OTHER_TYPE, DEST_LOCAL), create_privacy(2, STRING_TYPE, DEST_LOCAL));
+ assertStripByFields(DEST_EXPLICIT, expected, 2, create_privacy(1, OTHER_TYPE, DEST_LOCAL),
+ create_privacy(2, STRING_TYPE, DEST_LOCAL));
}
TEST_F(PrivacyBufferTest, StripVarintAndFixed64) {
- writeToFdBuffer(STRING_FIELD_0 + VARINT_FIELD_1 + STRING_FIELD_2
- + FIX64_FIELD_3 + FIX32_FIELD_4);
+ writeToFdBuffer(STRING_FIELD_0 + VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3 +
+ FIX32_FIELD_4);
string expected = STRING_FIELD_0 + STRING_FIELD_2 + FIX32_FIELD_4;
- assertStripByFields(DEST_EXPLICIT, expected, 2,
- create_privacy(1, OTHER_TYPE, DEST_LOCAL), create_privacy(3, OTHER_TYPE, DEST_LOCAL));
+ assertStripByFields(DEST_EXPLICIT, expected, 2, create_privacy(1, OTHER_TYPE, DEST_LOCAL),
+ create_privacy(3, OTHER_TYPE, DEST_LOCAL));
}
TEST_F(PrivacyBufferTest, StripVarintInNestedMessage) {
writeToFdBuffer(STRING_FIELD_0 + MESSAGE_FIELD_5);
- Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL };
+ Privacy* list[] = {create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL};
string expected = STRING_FIELD_0 + "\x2a\xd" + STRING_FIELD_2;
assertStripByFields(DEST_EXPLICIT, expected, 1, create_message_privacy(5, list));
}
TEST_F(PrivacyBufferTest, StripFix64AndVarintInNestedMessage) {
writeToFdBuffer(STRING_FIELD_0 + FIX64_FIELD_3 + MESSAGE_FIELD_5);
- Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL };
+ Privacy* list[] = {create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL};
string expected = STRING_FIELD_0 + "\x2a\xd" + STRING_FIELD_2;
- assertStripByFields(DEST_EXPLICIT, expected, 2, create_privacy(3, OTHER_TYPE, DEST_LOCAL), create_message_privacy(5, list));
+ assertStripByFields(DEST_EXPLICIT, expected, 2, create_privacy(3, OTHER_TYPE, DEST_LOCAL),
+ create_message_privacy(5, list));
}
TEST_F(PrivacyBufferTest, ClearAndStrip) {
string data = STRING_FIELD_0 + VARINT_FIELD_1;
writeToFdBuffer(data);
- Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL };
+ Privacy* list[] = {create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL};
EncodedBuffer::iterator bufData = buffer.data();
PrivacyBuffer privacyBuf(create_message_privacy(300, list), bufData);
PrivacySpec spec1 = PrivacySpec::new_spec(DEST_EXPLICIT);
@@ -235,7 +238,7 @@ TEST_F(PrivacyBufferTest, ClearAndStrip) {
TEST_F(PrivacyBufferTest, BadDataInFdBuffer) {
writeToFdBuffer("iambaddata");
- Privacy* list[] = { create_privacy(4, OTHER_TYPE, DEST_AUTOMATIC), NULL };
+ Privacy* list[] = {create_privacy(4, OTHER_TYPE, DEST_AUTOMATIC), NULL};
EncodedBuffer::iterator bufData = buffer.data();
PrivacyBuffer privacyBuf(create_message_privacy(300, list), bufData);
PrivacySpec spec;
@@ -244,8 +247,8 @@ TEST_F(PrivacyBufferTest, BadDataInFdBuffer) {
TEST_F(PrivacyBufferTest, BadDataInNestedMessage) {
writeToFdBuffer(STRING_FIELD_0 + MESSAGE_FIELD_5 + "aoeoe");
- Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL };
- Privacy* field5[] = { create_message_privacy(5, list), NULL };
+ Privacy* list[] = {create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL};
+ Privacy* field5[] = {create_message_privacy(5, list), NULL};
EncodedBuffer::iterator bufData = buffer.data();
PrivacyBuffer privacyBuf(create_message_privacy(300, field5), bufData);
PrivacySpec spec;
@@ -256,7 +259,7 @@ TEST_F(PrivacyBufferTest, SelfRecursionMessage) {
string input = "\x2a\"" + VARINT_FIELD_1 + STRING_FIELD_2 + MESSAGE_FIELD_5;
writeToFdBuffer(input);
Privacy* field5 = create_message_privacy(5, NULL);
- Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), field5, NULL };
+ Privacy* list[] = {create_privacy(1, OTHER_TYPE, DEST_LOCAL), field5, NULL};
field5->children = list;
string expected = "\x2a\x1c" + STRING_FIELD_2 + "\x2a\xd" + STRING_FIELD_2;
assertStrip(DEST_EXPLICIT, expected, field5);
@@ -264,7 +267,7 @@ TEST_F(PrivacyBufferTest, SelfRecursionMessage) {
TEST_F(PrivacyBufferTest, AutoMessage) {
writeToFdBuffer(STRING_FIELD_2 + MESSAGE_FIELD_5);
- Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL };
+ Privacy* list[] = {create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL};
Privacy* autoMsg = create_privacy(5, MESSAGE_TYPE, DEST_AUTOMATIC);
autoMsg->children = list;
string expected = "\x2a\xd" + STRING_FIELD_2;
diff --git a/cmds/incidentd/tests/Reporter_test.cpp b/cmds/incidentd/tests/Reporter_test.cpp
index c494bd646b0b..bd359ac9516c 100644
--- a/cmds/incidentd/tests/Reporter_test.cpp
+++ b/cmds/incidentd/tests/Reporter_test.cpp
@@ -11,8 +11,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "Reporter.h"
@@ -26,7 +25,6 @@
#include <gtest/gtest.h>
#include <string.h>
-
using namespace android;
using namespace android::base;
using namespace android::binder;
@@ -35,8 +33,7 @@ using namespace std;
using ::testing::StrEq;
using ::testing::Test;
-class TestListener : public IIncidentReportStatusListener
-{
+class TestListener : public IIncidentReportStatusListener {
public:
int startInvoked;
int finishInvoked;
@@ -44,8 +41,8 @@ public:
map<int, int> startSections;
map<int, int> finishSections;
- TestListener() : startInvoked(0), finishInvoked(0), failedInvoked(0) {};
- virtual ~TestListener() {};
+ TestListener() : startInvoked(0), finishInvoked(0), failedInvoked(0){};
+ virtual ~TestListener(){};
virtual Status onReportStarted() {
startInvoked++;
@@ -53,16 +50,14 @@ public:
};
virtual Status onReportSectionStatus(int section, int status) {
switch (status) {
- case IIncidentReportStatusListener::STATUS_STARTING:
- if (startSections.count(section) == 0)
- startSections[section] = 0;
- startSections[section] = startSections[section] + 1;
- break;
- case IIncidentReportStatusListener::STATUS_FINISHED:
- if (finishSections.count(section) == 0)
- finishSections[section] = 0;
- finishSections[section] = finishSections[section] + 1;
- break;
+ case IIncidentReportStatusListener::STATUS_STARTING:
+ if (startSections.count(section) == 0) startSections[section] = 0;
+ startSections[section] = startSections[section] + 1;
+ break;
+ case IIncidentReportStatusListener::STATUS_FINISHED:
+ if (finishSections.count(section) == 0) finishSections[section] = 0;
+ finishSections[section] = finishSections[section] + 1;
+ break;
}
return Status::ok();
};
@@ -156,7 +151,8 @@ TEST_F(ReporterTest, RunReportWithHeaders) {
string result;
ReadFileToString(tf.path, &result);
- EXPECT_THAT(result, StrEq("\n\x2" "\b\f"));
+ EXPECT_THAT(result, StrEq("\n\x2"
+ "\b\f"));
EXPECT_EQ(l->startInvoked, 2);
EXPECT_EQ(l->finishInvoked, 2);
@@ -178,5 +174,24 @@ TEST_F(ReporterTest, RunReportToGivenDirectory) {
ASSERT_EQ(Reporter::REPORT_FINISHED, reporter->runReport());
vector<string> results = InspectFiles();
ASSERT_EQ((int)results.size(), 1);
- EXPECT_EQ(results[0], "\n\x2" "\b\f\n\x6" "\x12\x4" "abcd");
+ EXPECT_EQ(results[0],
+ "\n\x2"
+ "\b\f\n\x6"
+ "\x12\x4"
+ "abcd");
}
+
+TEST_F(ReporterTest, ReportMetadata) {
+ IncidentReportArgs args;
+ args.addSection(1);
+ args.setDest(android::os::DEST_EXPLICIT);
+ sp<ReportRequest> r = new ReportRequest(args, l, -1);
+ reporter->batch.add(r);
+
+ ASSERT_EQ(Reporter::REPORT_FINISHED, reporter->runReport());
+ auto metadata = reporter->batch.metadata();
+ EXPECT_EQ(IncidentMetadata_Destination_EXPLICIT, metadata.dest());
+ EXPECT_EQ(1, metadata.request_size());
+ EXPECT_TRUE(metadata.use_dropbox());
+ EXPECT_EQ(0, metadata.sections_size());
+} \ No newline at end of file
diff --git a/cmds/incidentd/tests/Section_test.cpp b/cmds/incidentd/tests/Section_test.cpp
index 2cfd7df6be84..a1f4fdc77300 100644
--- a/cmds/incidentd/tests/Section_test.cpp
+++ b/cmds/incidentd/tests/Section_test.cpp
@@ -11,13 +11,13 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "Section.h"
#include <android-base/file.h>
#include <android-base/test_utils.h>
+#include <android/os/IncidentReportArgs.h>
#include <frameworks/base/libs/incident/proto/android/os/header.pb.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -29,9 +29,9 @@ const int REVERSE_PARSER = 1;
const int QUICK_TIMEOUT_MS = 100;
-const string VARINT_FIELD_1 = "\x08\x96\x01"; // 150
+const string VARINT_FIELD_1 = "\x08\x96\x01"; // 150
const string STRING_FIELD_2 = "\x12\vwhatthefuck";
-const string FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff"; // -1
+const string FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff"; // -1
using namespace android::base;
using namespace android::binder;
@@ -43,11 +43,10 @@ using ::testing::internal::GetCapturedStdout;
// NOTICE: this test requires /system/bin/incident_helper is installed.
-class SimpleListener : public IIncidentReportStatusListener
-{
+class SimpleListener : public IIncidentReportStatusListener {
public:
- SimpleListener() {};
- virtual ~SimpleListener() {};
+ SimpleListener(){};
+ virtual ~SimpleListener(){};
virtual Status onReportStarted() { return Status::ok(); };
virtual Status onReportSectionStatus(int /*section*/, int /*status*/) { return Status::ok(); };
@@ -83,12 +82,26 @@ TEST(SectionTest, HeaderSection) {
string content;
CaptureStdout();
ASSERT_EQ(NO_ERROR, hs.Execute(&requests));
- EXPECT_THAT(GetCapturedStdout(), StrEq("\n\x5" "\x12\x3" "axe\n\x05\x12\x03pup"));
+ EXPECT_THAT(GetCapturedStdout(), StrEq("\n\x5"
+ "\x12\x3"
+ "axe\n\x05\x12\x03pup"));
EXPECT_TRUE(ReadFileToString(output2.path, &content));
EXPECT_THAT(content, StrEq("\n\x05\x12\x03pup"));
}
+TEST(SectionTest, MetadataSection) {
+ MetadataSection ms;
+ ReportRequestSet requests;
+
+ requests.setMainFd(STDOUT_FILENO);
+ requests.sectionStats(1)->set_success(true);
+
+ CaptureStdout();
+ ASSERT_EQ(NO_ERROR, ms.Execute(&requests));
+ EXPECT_THAT(GetCapturedStdout(), StrEq("\x12\b\x18\x1\"\x4\b\x1\x10\x1"));
+}
+
TEST(SectionTest, FileSection) {
TemporaryFile tf;
FileSection fs(REVERSE_PARSER, tf.path);
@@ -243,8 +256,9 @@ TEST(SectionTest, TestMultipleRequests) {
IncidentReportArgs args1, args2, args3;
args1.setAll(true);
- args1.setDest(0); // LOCAL
- args2.setAll(true); // default to explicit
+ args1.setDest(android::os::DEST_LOCAL);
+ args2.setAll(true);
+ args2.setDest(android::os::DEST_EXPLICIT);
sp<SimpleListener> l = new SimpleListener();
requests.add(new ReportRequest(args1, l, output1.fd));
requests.add(new ReportRequest(args2, l, output2.fd));
@@ -257,12 +271,12 @@ TEST(SectionTest, TestMultipleRequests) {
string content, expect;
expect = VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3;
- char c = (char) expect.size();
+ char c = (char)expect.size();
EXPECT_TRUE(ReadFileToString(output1.path, &content));
EXPECT_THAT(content, StrEq(string("\x02") + c + expect));
expect = STRING_FIELD_2 + FIX64_FIELD_3;
- c = (char) expect.size();
+ c = (char)expect.size();
EXPECT_TRUE(ReadFileToString(output2.path, &content));
EXPECT_THAT(content, StrEq(string("\x02") + c + expect));
@@ -283,10 +297,12 @@ TEST(SectionTest, TestMultipleRequestsBySpec) {
ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, input.path));
- IncidentReportArgs args1, args2, args3, args4;
+ IncidentReportArgs args1, args2, args3;
args1.setAll(true);
+ args1.setDest(android::os::DEST_EXPLICIT);
args2.setAll(true);
- args4.setAll(true);
+ args2.setDest(android::os::DEST_EXPLICIT);
+ args3.setAll(true);
sp<SimpleListener> l = new SimpleListener();
requests.add(new ReportRequest(args1, l, output1.fd));
requests.add(new ReportRequest(args2, l, output2.fd));
@@ -299,7 +315,7 @@ TEST(SectionTest, TestMultipleRequestsBySpec) {
string content, expect;
expect = STRING_FIELD_2 + FIX64_FIELD_3;
- char c = (char) expect.size();
+ char c = (char)expect.size();
// output1 and output2 are the same
EXPECT_TRUE(ReadFileToString(output1.path, &content));
@@ -307,7 +323,8 @@ TEST(SectionTest, TestMultipleRequestsBySpec) {
EXPECT_TRUE(ReadFileToString(output2.path, &content));
EXPECT_THAT(content, StrEq(string("\x02") + c + expect));
- // because args3 doesn't set section, so it should receive nothing
+ // output3 has only auto field
+ c = (char)STRING_FIELD_2.size();
EXPECT_TRUE(ReadFileToString(output3.path, &content));
- EXPECT_THAT(content, StrEq(""));
+ EXPECT_THAT(content, StrEq(string("\x02") + c + STRING_FIELD_2));
} \ No newline at end of file
diff --git a/cmds/incidentd/tests/section_list.cpp b/cmds/incidentd/tests/section_list.cpp
index 1d6213fd19b3..bd2d15cc38be 100644
--- a/cmds/incidentd/tests/section_list.cpp
+++ b/cmds/incidentd/tests/section_list.cpp
@@ -1,25 +1,17 @@
// This file is a dummy section_list.cpp used for test only.
#include "section_list.h"
-const Section* SECTION_LIST[] = {
- NULL
-};
+const Section* SECTION_LIST[] = {NULL};
-Privacy sub_field_1 { 1, 1, NULL, DEST_LOCAL, NULL };
-Privacy sub_field_2 { 2, 9, NULL, DEST_AUTOMATIC, NULL };
+Privacy sub_field_1{1, 1, NULL, DEST_LOCAL, NULL};
+Privacy sub_field_2{2, 9, NULL, DEST_AUTOMATIC, NULL};
-Privacy* list[] = {
- &sub_field_1,
- &sub_field_2,
- NULL };
+Privacy* list[] = {&sub_field_1, &sub_field_2, NULL};
-Privacy field_0 { 0, 11, list, DEST_EXPLICIT, NULL };
-Privacy field_1 { 1, 9, NULL, DEST_AUTOMATIC, NULL };
+Privacy field_0{0, 11, list, DEST_EXPLICIT, NULL};
+Privacy field_1{1, 9, NULL, DEST_AUTOMATIC, NULL};
-Privacy* final_list[] = {
- &field_0,
- &field_1
-};
+Privacy* final_list[] = {&field_0, &field_1};
const Privacy** PRIVACY_POLICY_LIST = const_cast<const Privacy**>(final_list);
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 67b9089c8315..740fdc0af5f1 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -116,10 +116,8 @@ LOCAL_SRC_FILES := \
LOCAL_CFLAGS += \
-Wall \
+ -Wextra \
-Werror \
- -Wno-missing-field-initializers \
- -Wno-unused-variable \
- -Wno-unused-function \
-Wno-unused-parameter
ifeq (debug,)
diff --git a/cmds/statsd/OWNERS b/cmds/statsd/OWNERS
new file mode 100644
index 000000000000..362d411d03a5
--- /dev/null
+++ b/cmds/statsd/OWNERS
@@ -0,0 +1,6 @@
+bookatz@google.com
+jinyithu@google.com
+kwekua@google.com
+stlafon@google.com
+yaochen@google.com
+yanglu@google.com
diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp
index 7b0b69a4bcae..6894bcf53e79 100644
--- a/cmds/statsd/src/FieldValue.cpp
+++ b/cmds/statsd/src/FieldValue.cpp
@@ -23,6 +23,23 @@ namespace android {
namespace os {
namespace statsd {
+int32_t getEncodedField(int32_t pos[], int32_t depth, bool includeDepth) {
+ int32_t field = 0;
+ for (int32_t i = 0; i <= depth; i++) {
+ int32_t shiftBits = 8 * (kMaxLogDepth - i);
+ field |= (pos[i] << shiftBits);
+ }
+
+ if (includeDepth) {
+ field |= (depth << 24);
+ }
+ return field;
+}
+
+int32_t encodeMatcherMask(int32_t mask[], int32_t depth) {
+ return getEncodedField(mask, depth, false) | 0xff000000;
+}
+
bool Field::matches(const Matcher& matcher) const {
if (mTag != matcher.mMatcher.getTag()) {
return false;
@@ -32,7 +49,7 @@ bool Field::matches(const Matcher& matcher) const {
}
return false;
-};
+}
void translateFieldMatcher(int tag, const FieldMatcher& matcher, int depth, int* pos, int* mask,
std::vector<Matcher>* output) {
@@ -71,7 +88,6 @@ void translateFieldMatcher(int tag, const FieldMatcher& matcher, int depth, int*
if (matcher.child_size() == 0) {
output->push_back(Matcher(Field(tag, pos, depth), encodeMatcherMask(mask, depth)));
- Matcher matcher = Matcher(Field(tag, pos, depth), encodeMatcherMask(mask, depth));
} else {
for (const auto& child : matcher.child()) {
translateFieldMatcher(tag, child, depth + 1, pos, mask, output);
diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h
index 7484108d9e1a..d17dded8d691 100644
--- a/cmds/statsd/src/FieldValue.h
+++ b/cmds/statsd/src/FieldValue.h
@@ -33,29 +33,14 @@ const int32_t kClearLastBitDeco = 0x7f;
enum Type { INT, LONG, FLOAT, STRING };
+int32_t getEncodedField(int32_t pos[], int32_t depth, bool includeDepth);
-static int32_t getEncodedField(int32_t pos[], int32_t depth, bool includeDepth) {
- int32_t field = 0;
- for (int32_t i = 0; i <= depth; i++) {
- int32_t shiftBits = 8 * (kMaxLogDepth - i);
- field |= (pos[i] << shiftBits);
- }
-
- if (includeDepth) {
- field |= (depth << 24);
- }
- return field;
-}
-
-static int32_t encodeMatcherMask(int32_t mask[], int32_t depth) {
- return getEncodedField(mask, depth, false) | 0xff000000;
-}
+int32_t encodeMatcherMask(int32_t mask[], int32_t depth);
// Get the encoded field for a leaf with a [field] number at depth 0;
-static int32_t getSimpleField(size_t field) {
+inline int32_t getSimpleField(size_t field) {
return ((int32_t)field << 8 * 2);
}
-
/**
* Field is a wrapper class for 2 integers that represents the field of a log element in its Atom
* proto.
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index 68e2176c2e6d..d901bd669591 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -68,7 +68,6 @@ bool filterValues(const vector<Matcher>& matcherFields, const vector<FieldValue>
for (const auto& value : values) {
// TODO: potential optimization here to break early because all fields are naturally
// sorted.
- int32_t filteredField;
if (value.mField.matches(matcher)) {
matchedResults.push_back(FieldValue(
Field(value.mField.getTag(), (value.mField.getField() & matcher.mMask)),
@@ -148,7 +147,6 @@ void filterGaugeValues(const std::vector<Matcher>& matcherFields,
const std::vector<FieldValue>& values, std::vector<FieldValue>* output) {
for (const auto& field : matcherFields) {
for (const auto& value : values) {
- int filteredField;
if (value.mField.matches(field)) {
output->push_back(value);
}
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 3a20b12500ae..87dec5d1656d 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -21,6 +21,7 @@
#include <android-base/file.h>
#include <dirent.h>
#include "StatsLogProcessor.h"
+#include "stats_log_util.h"
#include "android-base/stringprintf.h"
#include "guardrail/StatsdStats.h"
#include "metrics/CountMetricProducer.h"
@@ -57,10 +58,10 @@ const int FIELD_ID_REPORTS = 2;
const int FIELD_ID_UID = 1;
const int FIELD_ID_ID = 2;
// for ConfigMetricsReport
-const int FIELD_ID_METRICS = 1;
+// const int FIELD_ID_METRICS = 1; // written in MetricsManager.cpp
const int FIELD_ID_UID_MAP = 2;
-const int FIELD_ID_LAST_REPORT_NANOS = 3;
-const int FIELD_ID_CURRENT_REPORT_NANOS = 4;
+const int FIELD_ID_LAST_REPORT_ELAPSED_NANOS = 3;
+const int FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS = 4;
#define STATS_DATA_DIR "/data/misc/stats-data"
@@ -136,7 +137,7 @@ void StatsLogProcessor::onIsolatedUidChangedEventLocked(const LogEvent& event) {
void StatsLogProcessor::OnLogEvent(LogEvent* event) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
StatsdStats::getInstance().noteAtomLogged(
- event->GetTagId(), event->GetTimestampNs() / NS_PER_SEC);
+ event->GetTagId(), event->GetElapsedTimestampNs() / NS_PER_SEC);
// Hard-coded logic to update the isolated uid's in the uid-map.
// The field numbers need to be currently updated by hand with atoms.proto
@@ -148,10 +149,10 @@ void StatsLogProcessor::OnLogEvent(LogEvent* event) {
return;
}
- long curTime = time(nullptr);
- if (curTime - mLastPullerCacheClearTimeSec > StatsdStats::kPullerCacheClearIntervalSec) {
- mStatsPullerManager.ClearPullerCacheIfNecessary(curTime);
- mLastPullerCacheClearTimeSec = curTime;
+ uint64_t curTimeSec = getElapsedRealtimeSec();
+ if (curTimeSec - mLastPullerCacheClearTimeSec > StatsdStats::kPullerCacheClearIntervalSec) {
+ mStatsPullerManager.ClearPullerCacheIfNecessary(curTimeSec);
+ mLastPullerCacheClearTimeSec = curTimeSec;
}
if (event->GetTagId() != android::util::ISOLATED_UID_CHANGED) {
@@ -162,7 +163,7 @@ void StatsLogProcessor::OnLogEvent(LogEvent* event) {
// pass the event to metrics managers.
for (auto& pair : mMetricsManagers) {
pair.second->onLogEvent(*event);
- flushIfNecessaryLocked(event->GetTimestampNs(), pair.first, *(pair.second));
+ flushIfNecessaryLocked(event->GetElapsedTimestampNs(), pair.first, *(pair.second));
}
}
@@ -242,6 +243,7 @@ void StatsLogProcessor::onDumpReportLocked(const ConfigKey& key, const uint64_t
long long reportsToken =
proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS);
+ int64_t lastReportTimeNs = it->second->getLastReportTimeNs();
// First, fill in ConfigMetricsReport using current data on memory, which
// starts from filling in StatsLogReport's.
it->second->onDumpReport(dumpTimeStampNs, &proto);
@@ -254,10 +256,10 @@ void StatsLogProcessor::onDumpReportLocked(const ConfigKey& key, const uint64_t
proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP, uidMapBuffer, uidMapSize);
// Fill in the timestamps.
- proto.write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_NANOS,
- (long long)it->second->getLastReportTimeNs());
- proto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_NANOS,
- (long long)::android::elapsedRealtimeNano());
+ proto.write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_ELAPSED_NANOS,
+ (long long)lastReportTimeNs);
+ proto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS,
+ (long long)dumpTimeStampNs);
// End of ConfigMetricsReport (reports).
proto.end(reportsToken);
@@ -340,8 +342,8 @@ void StatsLogProcessor::WriteDataToDisk() {
vector<uint8_t> data;
onDumpReportLocked(key, time(nullptr) * NS_PER_SEC, &data);
// TODO: Add a guardrail to prevent accumulation of file on disk.
- string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR, time(nullptr),
- key.GetUid(), (long long)key.GetId());
+ string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR,
+ (long)getWallClockSec(), key.GetUid(), (long long)key.GetId());
StorageManager::writeFile(file_name.c_str(), &data[0], data.size());
}
}
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index ee38667b0df9..791fb14a7717 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -18,6 +18,7 @@
#include "Log.h"
#include "StatsService.h"
+#include "stats_log_util.h"
#include "android-base/stringprintf.h"
#include "config/ConfigKey.h"
#include "config/ConfigManager.h"
@@ -79,18 +80,20 @@ StatsService::StatsService(const sp<Looper>& handlerLooper)
mUidMap = new UidMap();
StatsPuller::SetUidMap(mUidMap);
mConfigManager = new ConfigManager();
- mProcessor = new StatsLogProcessor(mUidMap, mAnomalyMonitor, time(nullptr), [this](const ConfigKey& key) {
- sp<IStatsCompanionService> sc = getStatsCompanionService();
- auto receiver = mConfigManager->GetConfigReceiver(key);
- if (sc == nullptr) {
- VLOG("Could not find StatsCompanionService");
- } else if (receiver == nullptr) {
- VLOG("Statscompanion could not find a broadcast receiver for %s",
- key.ToString().c_str());
- } else {
- sc->sendDataBroadcast(receiver);
+ mProcessor = new StatsLogProcessor(mUidMap, mAnomalyMonitor, getElapsedRealtimeSec(),
+ [this](const ConfigKey& key) {
+ sp<IStatsCompanionService> sc = getStatsCompanionService();
+ auto receiver = mConfigManager->GetConfigReceiver(key);
+ if (sc == nullptr) {
+ VLOG("Could not find StatsCompanionService");
+ } else if (receiver == nullptr) {
+ VLOG("Statscompanion could not find a broadcast receiver for %s",
+ key.ToString().c_str());
+ } else {
+ sc->sendDataBroadcast(receiver);
+ }
}
- });
+ );
mConfigManager->AddListener(mProcessor);
@@ -121,8 +124,6 @@ void StatsService::init_build_type_callback(void* cookie, const char* /*name*/,
*/
status_t StatsService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
uint32_t flags) {
- status_t err;
-
switch (code) {
case SHELL_COMMAND_TRANSACTION: {
int in = data.readFileDescriptor();
@@ -237,8 +238,8 @@ status_t StatsService::command(FILE* in, FILE* out, FILE* err, Vector<String8>&
return cmd_write_data_to_disk(out);
}
- if (!args[0].compare(String8("log-app-hook"))) {
- return cmd_log_app_hook(out, args);
+ if (!args[0].compare(String8("log-app-breadcrumb"))) {
+ return cmd_log_app_breadcrumb(out, args);
}
if (!args[0].compare(String8("clear-puller-cache"))) {
@@ -281,8 +282,8 @@ void StatsService::print_cmd_help(FILE* out) {
fprintf(out, " Flushes all data on memory to disk.\n");
fprintf(out, "\n");
fprintf(out, "\n");
- fprintf(out, "usage: adb shell cmd stats log-app-hook [UID] LABEL STATE\n");
- fprintf(out, " Writes an AppHook event to the statslog buffer.\n");
+ fprintf(out, "usage: adb shell cmd stats log-app-breadcrumb [UID] LABEL STATE\n");
+ fprintf(out, " Writes an AppBreadcrumbReported event to the statslog buffer.\n");
fprintf(out, " UID The uid to use. It is only possible to pass a UID\n");
fprintf(out, " parameter on eng builds. If UID is omitted the calling\n");
fprintf(out, " uid is used.\n");
@@ -548,7 +549,7 @@ status_t StatsService::cmd_write_data_to_disk(FILE* out) {
return NO_ERROR;
}
-status_t StatsService::cmd_log_app_hook(FILE* out, const Vector<String8>& args) {
+status_t StatsService::cmd_log_app_breadcrumb(FILE* out, const Vector<String8>& args) {
bool good = false;
int32_t uid;
int32_t label;
@@ -570,13 +571,13 @@ status_t StatsService::cmd_log_app_hook(FILE* out, const Vector<String8>& args)
good = true;
} else {
fprintf(out,
- "Selecting a UID for writing AppHook can only be dumped for other UIDs on eng"
- " or userdebug builds.\n");
+ "Selecting a UID for writing AppBreadcrumb can only be done for other UIDs "
+ "on eng or userdebug builds.\n");
}
}
if (good) {
- fprintf(out, "Logging AppHook(%d, %d, %d) to statslog.\n", uid, label, state);
- android::util::stats_write(android::util::APP_HOOK, uid, label, state);
+ fprintf(out, "Logging AppBreadcrumbReported(%d, %d, %d) to statslog.\n", uid, label, state);
+ android::util::stats_write(android::util::APP_BREADCRUMB_REPORTED, uid, label, state);
} else {
print_cmd_help(out);
return UNKNOWN_ERROR;
@@ -668,11 +669,7 @@ Status StatsService::informAnomalyAlarmFired() {
return Status::fromExceptionCode(Status::EX_SECURITY,
"Only system uid can call informAnomalyAlarmFired");
}
-
- // TODO: This may be a bug. time(nullptr) can be off (wrt AlarmManager's time) and cause us to
- // miss the alarm! Eventually we will switch to using elapsedRealTime everywhere,
- // which may hopefully fix the problem, so we'll leave this alone for now.
- uint64_t currentTimeSec = time(nullptr);
+ uint64_t currentTimeSec = getElapsedRealtimeSec();
std::unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> anomalySet =
mAnomalyMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
if (anomalySet.size() > 0) {
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 3dc19fe08d94..9690de702c24 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -193,9 +193,10 @@ private:
status_t cmd_write_data_to_disk(FILE* out);
/**
- * Write an AppHook event to the StatsLog buffer, as though StatsLog.write(APP_HOOK).
+ * Write an AppBreadcrumbReported event to the StatsLog buffer, as if calling
+ * StatsLog.write(APP_BREADCRUMB_REPORTED).
*/
- status_t cmd_log_app_hook(FILE* out, const Vector<String8>& args);
+ status_t cmd_log_app_breadcrumb(FILE* out, const Vector<String8>& args);
/**
* Print contents of a pulled metrics source.
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 4c6a36bd9270..85e209be6413 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -85,7 +85,7 @@ message Atom {
PacketWakeupOccurred packet_wakeup_occurred = 44;
DropboxErrorChanged dropbox_error_changed = 45;
AnomalyDetected anomaly_detected = 46;
- AppHook app_hook = 47;
+ AppBreadcrumbReported app_breadcrumb_reported = 47;
AppStartChanged app_start_changed = 48;
AppStartCancelChanged app_start_cancel_changed = 49;
AppStartFullyDrawnChanged app_start_fully_drawn_changed = 50;
@@ -202,9 +202,10 @@ message UidProcessStateChanged {
* frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
*/
message ProcessLifeCycleStateChanged {
- optional int32 uid = 1; // TODO: should be a string tagged w/ uid annotation
+ // TODO: should be a string tagged w/ uid annotation
+ optional int32 uid = 1;
- // TODO: What is this?
+ // The process name (usually same as the app name).
optional string name = 2;
// What lifecycle state the process changed to.
@@ -312,7 +313,7 @@ message GpsScanStateChanged {
message SyncStateChanged {
repeated AttributionNode attribution_node = 1;
- // Name of the sync (as named in the app)
+ // Name of the sync (as named in the app). Can be chosen at run-time.
optional string name = 2;
enum State {
@@ -615,7 +616,7 @@ message KernelWakeupReported {
optional string wakeup_reason_name = 1;
// Duration (in microseconds) for the wake-up interrupt to be serviced.
- optional int64 duration_usec = 2;
+ optional int64 duration_micros = 2;
}
/**
@@ -692,10 +693,10 @@ message ShutdownSequenceReported {
// Beginning of shutdown time in ms using wall clock time since unix epoch.
// Default: 0 if no start time received.
- optional int64 start_time_ms = 3;
+ optional int64 start_time_millis = 3;
// Duration of shutdown in ms. Default: 0 if no duration received.
- optional int64 duration_ms = 4;
+ optional int64 duration_millis = 4;
}
@@ -715,13 +716,13 @@ message BootSequenceReported {
optional string system_reason = 2;
// End of boot time in ms from unix epoch using system wall clock.
- optional int64 end_time_ms = 3;
+ optional int64 end_time_millis = 3;
// Total boot duration in ms.
- optional int64 total_duration_ms = 4;
+ optional int64 total_duration_millis = 4;
// Bootloader duration in ms.
- optional int64 bootloader_duration_ms = 5;
+ optional int64 bootloader_duration_millis = 5;
// Time since last boot in ms. Default: 0 if not available.
optional int64 time_since_last_boot = 6;
@@ -762,7 +763,7 @@ message CallStateChanged {
*/
message DaveyOccurred {
// Amount of time it took to render the frame. Should be >=700ms.
- optional int64 jank_duration_ms = 1;
+ optional int64 jank_duration_millis = 1;
}
/**
@@ -863,7 +864,7 @@ message DropboxErrorChanged {
* Logged from:
* frameworks/base/core/java/android/util/StatsLog.java
*/
-message AppHook {
+message AppBreadcrumbReported {
// The uid of the application that sent this custom atom.
optional int32 uid = 1;
@@ -924,16 +925,16 @@ message AppStartChanged {
optional bool is_instant_app = 6;
// Device uptime when activity started.
- optional int64 activity_start_msec = 7;
+ optional int64 activity_start_millis = 7;
optional android.app.AppTransitionReasonEnum reason = 8;
- optional int32 transition_delay_msec = 9;
+ optional int32 transition_delay_millis = 9;
// -1 if not set.
- optional int32 starting_window_delay_msec = 10;
+ optional int32 starting_window_delay_millis = 10;
// -1 if not set.
- optional int32 bind_application_delay_msec = 11;
- optional int32 windows_drawn_delay_msec = 12;
+ optional int32 bind_application_delay_millis = 11;
+ optional int32 windows_drawn_delay_millis = 12;
// Empty if not set.
optional string launch_token = 13;
@@ -981,7 +982,7 @@ message AppStartFullyDrawnChanged {
optional bool transition_process_running = 5;
// App startup time (until call to Activity#reportFullyDrawn()).
- optional int64 app_startup_time_ms = 6;
+ optional int64 app_startup_time_millis = 6;
}
/**
@@ -1303,7 +1304,7 @@ message SubsystemSleepState {
// The number of times it entered, or voted for entering the sleep state
optional uint64 count = 3;
// The length of time spent in, or spent voting for, the sleep state
- optional uint64 timeMs = 4;
+ optional uint64 time_millis = 4;
}
/**
@@ -1316,7 +1317,7 @@ message SubsystemSleepState {
message CpuTimePerFreq {
optional uint32 cluster = 1;
optional uint32 freq_index = 2;
- optional uint64 time_ms = 3;
+ optional uint64 time_millis = 3;
}
/**
@@ -1325,8 +1326,8 @@ message CpuTimePerFreq {
*/
message CpuTimePerUid {
optional uint64 uid = 1;
- optional uint64 user_time_ms = 2;
- optional uint64 sys_time_ms = 3;
+ optional uint64 user_time_millis = 2;
+ optional uint64 sys_time_millis = 3;
}
/**
@@ -1337,7 +1338,7 @@ message CpuTimePerUid {
message CpuTimePerUidFreq {
optional uint64 uid = 1;
optional uint64 freq_idx = 2;
- optional uint64 time_ms = 3;
+ optional uint64 time_millis = 3;
}
/**
@@ -1345,16 +1346,16 @@ message CpuTimePerUidFreq {
*/
message WifiActivityEnergyInfo {
// timestamp(wall clock) of record creation
- optional uint64 timestamp_ms = 1;
+ optional uint64 timestamp_millis = 1;
// stack reported state
// TODO: replace this with proto enum
optional int32 stack_state = 2;
// tx time in ms
- optional uint64 controller_tx_time_ms = 3;
+ optional uint64 controller_tx_time_millis = 3;
// rx time in ms
- optional uint64 controller_rx_time_ms = 4;
+ optional uint64 controller_rx_time_millis = 4;
// idle time in ms
- optional uint64 controller_idle_time_ms = 5;
+ optional uint64 controller_idle_time_millis = 5;
// product of current(mA), voltage(V) and time(ms)
optional uint64 controller_energy_used = 6;
}
@@ -1364,11 +1365,11 @@ message WifiActivityEnergyInfo {
*/
message ModemActivityInfo {
// timestamp(wall clock) of record creation
- optional uint64 timestamp_ms = 1;
+ optional uint64 timestamp_millis = 1;
// sleep time in ms.
- optional uint64 sleep_time_ms = 2;
+ optional uint64 sleep_time_millis = 2;
// idle time in ms
- optional uint64 controller_idle_time_ms = 3;
+ optional uint64 controller_idle_time_millis = 3;
/**
* Tx power index
* index 0 = tx_power < 0dBm
@@ -1378,17 +1379,17 @@ message ModemActivityInfo {
* index 4 = tx_power > 20dBm
*/
// tx time in ms at power level 0
- optional uint64 controller_tx_time_pl0_ms = 4;
+ optional uint64 controller_tx_time_pl0_millis = 4;
// tx time in ms at power level 1
- optional uint64 controller_tx_time_pl1_ms = 5;
+ optional uint64 controller_tx_time_pl1_millis = 5;
// tx time in ms at power level 2
- optional uint64 controller_tx_time_pl2_ms = 6;
+ optional uint64 controller_tx_time_pl2_millis = 6;
// tx time in ms at power level 3
- optional uint64 controller_tx_time_pl3_ms = 7;
+ optional uint64 controller_tx_time_pl3_millis = 7;
// tx time in ms at power level 4
- optional uint64 controller_tx_time_pl4_ms = 8;
+ optional uint64 controller_tx_time_pl4_millis = 8;
// rx time in ms at power level 5
- optional uint64 controller_rx_time_ms = 9;
+ optional uint64 controller_rx_time_millis = 9;
// product of current(mA), voltage(V) and time(ms)
optional uint64 energy_used = 10;
}
@@ -1399,15 +1400,15 @@ message ModemActivityInfo {
*/
message BluetoothActivityInfo {
// timestamp(wall clock) of record creation
- optional uint64 timestamp_ms = 1;
+ optional uint64 timestamp_millis = 1;
// bluetooth stack state
optional int32 bluetooth_stack_state = 2;
// tx time in ms
- optional uint64 controller_tx_time_ms = 3;
+ optional uint64 controller_tx_time_millis = 3;
// rx time in ms
- optional uint64 controller_rx_time_ms = 4;
+ optional uint64 controller_rx_time_millis = 4;
// idle time in ms
- optional uint64 controller_idle_time_ms = 5;
+ optional uint64 controller_idle_time_millis = 5;
// product of current(mA), voltage(V) and time(ms)
optional uint64 energy_used = 6;
}
@@ -1445,7 +1446,7 @@ message ProcessMemoryState {
* Elapsed real time from SystemClock.
*/
message SystemElapsedRealtime {
- optional uint64 time_ms = 1;
+ optional uint64 time_millis = 1;
}
/*
@@ -1456,7 +1457,7 @@ message SystemUptime {
// This clock stops when the system enters deep sleep (CPU off, display dark, device waiting
// for external input).
// It is not affected by clock scaling, idle, or other power saving mechanisms.
- optional uint64 uptime_ms = 1;
+ optional uint64 uptime_millis = 1;
}
/*
@@ -1470,8 +1471,9 @@ message SystemUptime {
*/
message CpuActiveTime {
optional uint64 uid = 1;
- optional uint64 idx = 2;
- optional uint64 time_ms = 3;
+ optional uint32 cluster_number = 2;
+ optional uint64 idx = 3;
+ optional uint64 time_millis = 4;
}
/**
@@ -1486,7 +1488,7 @@ message CpuActiveTime {
message CpuClusterTime {
optional uint64 uid = 1;
optional uint64 idx = 2;
- optional uint64 time_ms = 3;
+ optional uint64 time_millis = 3;
}
/*
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 06ff603f083f..d0f55abe7033 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -59,71 +59,106 @@ void ConfigManager::StartupForTest() {
}
void ConfigManager::AddListener(const sp<ConfigListener>& listener) {
+ lock_guard<mutex> lock(mMutex);
mListeners.push_back(listener);
}
void ConfigManager::UpdateConfig(const ConfigKey& key, const StatsdConfig& config) {
- // Add to set
- mConfigs.insert(key);
+ vector<sp<ConfigListener>> broadcastList;
+ {
+ lock_guard <mutex> lock(mMutex);
- // Save to disk
- update_saved_configs(key, config);
+ // Add to set
+ mConfigs.insert(key);
+
+ // Save to disk
+ update_saved_configs_locked(key, config);
+
+ for (sp<ConfigListener> listener : mListeners) {
+ broadcastList.push_back(listener);
+ }
+ }
// Tell everyone
- for (auto& listener : mListeners) {
+ for (sp<ConfigListener> listener:broadcastList) {
listener->OnConfigUpdated(key, config);
}
}
void ConfigManager::SetConfigReceiver(const ConfigKey& key, const sp<IBinder>& intentSender) {
+ lock_guard<mutex> lock(mMutex);
mConfigReceivers[key] = intentSender;
}
void ConfigManager::RemoveConfigReceiver(const ConfigKey& key) {
+ lock_guard<mutex> lock(mMutex);
mConfigReceivers.erase(key);
}
void ConfigManager::RemoveConfig(const ConfigKey& key) {
- auto it = mConfigs.find(key);
- if (it != mConfigs.end()) {
- // Remove from map
- mConfigs.erase(it);
+ vector<sp<ConfigListener>> broadcastList;
+ {
+ lock_guard <mutex> lock(mMutex);
+
+ auto it = mConfigs.find(key);
+ if (it != mConfigs.end()) {
+ // Remove from map
+ mConfigs.erase(it);
+
+ for (sp<ConfigListener> listener : mListeners) {
+ broadcastList.push_back(listener);
+ }
+ }
- // Tell everyone
- for (auto& listener : mListeners) {
- listener->OnConfigRemoved(key);
+ auto itReceiver = mConfigReceivers.find(key);
+ if (itReceiver != mConfigReceivers.end()) {
+ // Remove from map
+ mConfigReceivers.erase(itReceiver);
}
+
+ // Remove from disk. There can still be a lingering file on disk so we check
+ // whether or not the config was on memory.
+ remove_saved_configs(key);
}
- // Remove from disk. There can still be a lingering file on disk so we check
- // whether or not the config was on memory.
- remove_saved_configs(key);
+ for (sp<ConfigListener> listener:broadcastList) {
+ listener->OnConfigRemoved(key);
+ }
}
void ConfigManager::remove_saved_configs(const ConfigKey& key) {
- string suffix = StringPrintf("%d-%lld", key.GetUid(), (long long)key.GetId());
+ string suffix = StringPrintf("%d_%lld", key.GetUid(), (long long)key.GetId());
StorageManager::deleteSuffixedFiles(STATS_SERVICE_DIR, suffix.c_str());
}
void ConfigManager::RemoveConfigs(int uid) {
vector<ConfigKey> removed;
+ vector<sp<ConfigListener>> broadcastList;
+ {
+ lock_guard <mutex> lock(mMutex);
+
+
+ for (auto it = mConfigs.begin(); it != mConfigs.end();) {
+ // Remove from map
+ if (it->GetUid() == uid) {
+ remove_saved_configs(*it);
+ removed.push_back(*it);
+ mConfigReceivers.erase(*it);
+ it = mConfigs.erase(it);
+ } else {
+ it++;
+ }
+ }
- for (auto it = mConfigs.begin(); it != mConfigs.end();) {
- // Remove from map
- if (it->GetUid() == uid) {
- remove_saved_configs(*it);
- removed.push_back(*it);
- mConfigReceivers.erase(*it);
- it = mConfigs.erase(it);
- } else {
- it++;
+ for (sp<ConfigListener> listener : mListeners) {
+ broadcastList.push_back(listener);
}
}
// Remove separately so if they do anything in the callback they can't mess up our iteration.
for (auto& key : removed) {
// Tell everyone
- for (auto& listener : mListeners) {
+ for (sp<ConfigListener> listener:broadcastList) {
listener->OnConfigRemoved(key);
}
}
@@ -131,27 +166,38 @@ void ConfigManager::RemoveConfigs(int uid) {
void ConfigManager::RemoveAllConfigs() {
vector<ConfigKey> removed;
+ vector<sp<ConfigListener>> broadcastList;
+ {
+ lock_guard <mutex> lock(mMutex);
- for (auto it = mConfigs.begin(); it != mConfigs.end();) {
- // Remove from map
- removed.push_back(*it);
- auto receiverIt = mConfigReceivers.find(*it);
- if (receiverIt != mConfigReceivers.end()) {
- mConfigReceivers.erase(*it);
+
+ for (auto it = mConfigs.begin(); it != mConfigs.end();) {
+ // Remove from map
+ removed.push_back(*it);
+ auto receiverIt = mConfigReceivers.find(*it);
+ if (receiverIt != mConfigReceivers.end()) {
+ mConfigReceivers.erase(*it);
+ }
+ it = mConfigs.erase(it);
+ }
+
+ for (sp<ConfigListener> listener : mListeners) {
+ broadcastList.push_back(listener);
}
- it = mConfigs.erase(it);
}
// Remove separately so if they do anything in the callback they can't mess up our iteration.
for (auto& key : removed) {
// Tell everyone
- for (auto& listener : mListeners) {
+ for (sp<ConfigListener> listener:broadcastList) {
listener->OnConfigRemoved(key);
}
}
}
vector<ConfigKey> ConfigManager::GetAllConfigKeys() const {
+ lock_guard<mutex> lock(mMutex);
+
vector<ConfigKey> ret;
for (auto it = mConfigs.cbegin(); it != mConfigs.cend(); ++it) {
ret.push_back(*it);
@@ -160,6 +206,8 @@ vector<ConfigKey> ConfigManager::GetAllConfigKeys() const {
}
const sp<android::IBinder> ConfigManager::GetConfigReceiver(const ConfigKey& key) const {
+ lock_guard<mutex> lock(mMutex);
+
auto it = mConfigReceivers.find(key);
if (it == mConfigReceivers.end()) {
return nullptr;
@@ -169,6 +217,8 @@ const sp<android::IBinder> ConfigManager::GetConfigReceiver(const ConfigKey& key
}
void ConfigManager::Dump(FILE* out) {
+ lock_guard<mutex> lock(mMutex);
+
fprintf(out, "CONFIGURATIONS (%d)\n", (int)mConfigs.size());
fprintf(out, " uid name\n");
for (const auto& key : mConfigs) {
@@ -180,7 +230,7 @@ void ConfigManager::Dump(FILE* out) {
}
}
-void ConfigManager::update_saved_configs(const ConfigKey& key, const StatsdConfig& config) {
+void ConfigManager::update_saved_configs_locked(const ConfigKey& key, const StatsdConfig& config) {
// If there is a pre-existing config with same key we should first delete it.
remove_saved_configs(key);
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
index a2b2a0ce43d5..a0c1c1cb16f8 100644
--- a/cmds/statsd/src/config/ConfigManager.h
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -21,6 +21,7 @@
#include "config/ConfigListener.h"
#include <map>
+#include <mutex>
#include <set>
#include <string>
@@ -109,10 +110,12 @@ public:
void Dump(FILE* out);
private:
+ mutable std::mutex mMutex;
+
/**
* Save the configs to disk.
*/
- void update_saved_configs(const ConfigKey& key, const StatsdConfig& config);
+ void update_saved_configs_locked(const ConfigKey& key, const StatsdConfig& config);
/**
* Remove saved configs from disk.
diff --git a/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp b/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
index d0d2f938cf0c..d1d9d3778267 100644
--- a/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
+++ b/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
@@ -25,6 +25,7 @@
#include "guardrail/StatsdStats.h"
#include "logd/LogEvent.h"
#include "statslog.h"
+#include "stats_log_util.h"
using std::make_shared;
using std::shared_ptr;
@@ -62,7 +63,9 @@ bool CpuTimePerUidFreqPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
return false;
}
- uint64_t timestamp = time(nullptr) * NS_PER_SEC;
+ int64_t wallClockTimestampNs = getWallClockNs();
+ int64_t elapsedTimestampNs = getElapsedRealtimeNs();
+
char buf[kLineBufferSize];
// first line prints the format and frequencies
fin.getline(buf, kLineBufferSize);
@@ -77,7 +80,8 @@ bool CpuTimePerUidFreqPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
int idx = 0;
do {
timeMs = std::stoull(pch);
- auto ptr = make_shared<LogEvent>(android::util::CPU_TIME_PER_UID_FREQ, timestamp);
+ auto ptr = make_shared<LogEvent>(android::util::CPU_TIME_PER_UID_FREQ,
+ wallClockTimestampNs, elapsedTimestampNs);
ptr->write(uid);
ptr->write(idx);
ptr->write(timeMs);
diff --git a/cmds/statsd/src/external/CpuTimePerUidPuller.cpp b/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
index d9aeb4656bfe..568b8f0c0c53 100644
--- a/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
+++ b/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
@@ -24,6 +24,7 @@
#include "guardrail/StatsdStats.h"
#include "logd/LogEvent.h"
#include "statslog.h"
+#include "stats_log_util.h"
using std::make_shared;
using std::shared_ptr;
@@ -57,7 +58,8 @@ bool CpuTimePerUidPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
return false;
}
- uint64_t timestamp = time(nullptr) * NS_PER_SEC;
+ int64_t wallClockTimestampNs = getWallClockNs();
+ int64_t elapsedTimestampNs = getElapsedRealtimeNs();
char buf[kLineBufferSize];
char* pch;
while (!fin.eof()) {
@@ -70,7 +72,8 @@ bool CpuTimePerUidPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
pch = strtok(buf, " ");
uint64_t sysTimeMs = std::stoull(pch);
- auto ptr = make_shared<LogEvent>(android::util::CPU_TIME_PER_UID, timestamp);
+ auto ptr = make_shared<LogEvent>(android::util::CPU_TIME_PER_UID,
+ wallClockTimestampNs, elapsedTimestampNs);
ptr->write(uid);
ptr->write(userTimeMs);
ptr->write(sysTimeMs);
diff --git a/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp b/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp
index 0e126e7a4b44..0b545ccb3658 100644
--- a/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp
+++ b/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp
@@ -23,6 +23,7 @@
#include "guardrail/StatsdStats.h"
#include "logd/LogEvent.h"
#include "statslog.h"
+#include "stats_log_util.h"
using std::make_shared;
using std::shared_ptr;
@@ -57,7 +58,9 @@ bool KernelUidCpuActiveTimeReader::PullInternal(vector<shared_ptr<LogEvent>>* da
return false;
}
- uint64_t timestamp = time(nullptr) * NS_PER_SEC;
+ int64_t wallClockTimestampNs = getWallClockNs();
+ int64_t elapsedTimestampNs = getElapsedRealtimeNs();
+
char buf[kLineBufferSize];
char* pch;
while (!fin.eof()) {
@@ -70,7 +73,7 @@ bool KernelUidCpuActiveTimeReader::PullInternal(vector<shared_ptr<LogEvent>>* da
int idx = 0;
do {
timeMs = std::stoull(pch);
- auto ptr = make_shared<LogEvent>(mTagId, timestamp);
+ auto ptr = make_shared<LogEvent>(mTagId, wallClockTimestampNs, elapsedTimestampNs);
ptr->write(uid);
ptr->write(idx);
ptr->write(timeMs);
diff --git a/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp b/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp
index 7684ed4eb44b..cc80204b105e 100644
--- a/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp
+++ b/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp
@@ -22,6 +22,7 @@
#include "guardrail/StatsdStats.h"
#include "logd/LogEvent.h"
#include "statslog.h"
+#include "stats_log_util.h"
using std::make_shared;
using std::shared_ptr;
@@ -56,7 +57,8 @@ bool KernelUidCpuClusterTimeReader::PullInternal(vector<shared_ptr<LogEvent>>* d
return false;
}
- uint64_t timestamp = time(nullptr) * NS_PER_SEC;
+ int64_t wallClockTimestampNs = getWallClockNs();
+ int64_t elapsedTimestampNs = getElapsedRealtimeNs();
char buf[kLineBufferSize];
char* pch;
while (!fin.eof()) {
@@ -69,7 +71,7 @@ bool KernelUidCpuClusterTimeReader::PullInternal(vector<shared_ptr<LogEvent>>* d
int idx = 0;
do {
timeMs = std::stoull(pch);
- auto ptr = make_shared<LogEvent>(mTagId, timestamp);
+ auto ptr = make_shared<LogEvent>(mTagId, wallClockTimestampNs, elapsedTimestampNs);
ptr->write(uid);
ptr->write(idx);
ptr->write(timeMs);
diff --git a/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp b/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
index 72fb5ffd4b90..261cb4332dd6 100644
--- a/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
+++ b/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
@@ -25,6 +25,7 @@
#include "ResourceHealthManagerPuller.h"
#include "logd/LogEvent.h"
#include "statslog.h"
+#include "stats_log_util.h"
using android::hardware::hidl_vec;
using android::hardware::health::V2_0::get_health_service;
@@ -61,7 +62,8 @@ bool ResourceHealthManagerPuller::PullInternal(vector<shared_ptr<LogEvent>>* dat
return false;
}
- uint64_t timestamp = time(nullptr) * NS_PER_SEC;
+ int64_t wallClockTimestampNs = getWallClockNs();
+ int64_t elapsedTimestampNs = getElapsedRealtimeNs();
data->clear();
bool result_success = true;
@@ -72,12 +74,14 @@ bool ResourceHealthManagerPuller::PullInternal(vector<shared_ptr<LogEvent>>* dat
return;
}
if (mTagId == android::util::REMAINING_BATTERY_CAPACITY) {
- auto ptr = make_shared<LogEvent>(android::util::REMAINING_BATTERY_CAPACITY, timestamp);
+ auto ptr = make_shared<LogEvent>(android::util::REMAINING_BATTERY_CAPACITY,
+ wallClockTimestampNs, elapsedTimestampNs);
ptr->write(v.legacy.batteryChargeCounter);
ptr->init();
data->push_back(ptr);
} else if (mTagId == android::util::FULL_BATTERY_CAPACITY) {
- auto ptr = make_shared<LogEvent>(android::util::FULL_BATTERY_CAPACITY, timestamp);
+ auto ptr = make_shared<LogEvent>(android::util::FULL_BATTERY_CAPACITY,
+ wallClockTimestampNs, elapsedTimestampNs);
ptr->write(v.legacy.batteryFullCharge);
ptr->init();
data->push_back(ptr);
diff --git a/cmds/statsd/src/external/StatsCompanionServicePuller.cpp b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
index 8210c8dcd63d..bd859fd79a09 100644
--- a/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
+++ b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
@@ -22,6 +22,7 @@
#include <private/android_filesystem_config.h>
#include "StatsCompanionServicePuller.h"
#include "StatsService.h"
+#include "stats_log_util.h"
#include "guardrail/StatsdStats.h"
using namespace android;
@@ -53,13 +54,13 @@ bool StatsCompanionServicePuller::PullInternal(vector<shared_ptr<LogEvent> >* da
return false;
}
data->clear();
- int timestamp = time(nullptr);
+ int32_t timestampSec = getWallClockSec();
for (const StatsLogEventWrapper& it : returned_value) {
log_msg tmp;
tmp.entry_v1.len = it.bytes.size();
// Manually set the header size to 28 bytes to match the pushed log events.
tmp.entry.hdr_size = kLogMsgHeaderSize;
- tmp.entry_v1.sec = timestamp;
+ tmp.entry_v1.sec = timestampSec;
// And set the received bytes starting after the 28 bytes reserved for header.
std::copy(it.bytes.begin(), it.bytes.end(), tmp.buf + kLogMsgHeaderSize);
data->push_back(make_shared<LogEvent>(tmp));
diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp
index fc0ad7c5c3fc..9513cc521af7 100644
--- a/cmds/statsd/src/external/StatsPuller.cpp
+++ b/cmds/statsd/src/external/StatsPuller.cpp
@@ -20,6 +20,7 @@
#include "StatsPuller.h"
#include "guardrail/StatsdStats.h"
#include "puller_util.h"
+#include "stats_log_util.h"
namespace android {
namespace os {
@@ -44,7 +45,7 @@ StatsPuller::StatsPuller(const int tagId)
bool StatsPuller::Pull(std::vector<std::shared_ptr<LogEvent>>* data) {
lock_guard<std::mutex> lock(mLock);
StatsdStats::getInstance().notePull(mTagId);
- long curTime = time(nullptr);
+ long curTime = getElapsedRealtimeSec();
if (curTime - mLastPullTimeSec < mCoolDownSec) {
(*data) = mCachedData;
StatsdStats::getInstance().notePullFromCache(mTagId);
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
index 4c676a70363f..bee99396126d 100644
--- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
@@ -33,6 +33,7 @@
#include "SubsystemSleepStatePuller.h"
#include "logd/LogEvent.h"
#include "statslog.h"
+#include "stats_log_util.h"
#include <iostream>
@@ -114,7 +115,10 @@ const std::map<int, PullAtomInfo> StatsPullerManagerImpl::kAllPullAtomInfo = {
{{}, {}, 1, new ResourceHealthManagerPuller(android::util::REMAINING_BATTERY_CAPACITY)}},
// full_battery_capacity
{android::util::FULL_BATTERY_CAPACITY,
- {{}, {}, 1, new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}}};
+ {{}, {}, 1, new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}},
+ // process_memory_state
+ {android::util::PROCESS_MEMORY_STATE,
+ {{4,5,6,7,8}, {2,3}, 0, new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}}};
StatsPullerManagerImpl::StatsPullerManagerImpl()
: mCurrentPullingInterval(LONG_MAX) {
@@ -165,8 +169,9 @@ void StatsPullerManagerImpl::RegisterReceiver(int tagId, wp<PullDataReceiver> re
if (roundedIntervalMs < mCurrentPullingInterval) {
VLOG("Updating pulling interval %ld", intervalMs);
mCurrentPullingInterval = roundedIntervalMs;
- long currentTimeMs = time(nullptr) * 1000;
- long nextAlarmTimeMs = currentTimeMs + mCurrentPullingInterval - (currentTimeMs - mTimeBaseSec * 1000) % mCurrentPullingInterval;
+ long currentTimeMs = getElapsedRealtimeMillis();
+ long nextAlarmTimeMs = currentTimeMs + mCurrentPullingInterval -
+ (currentTimeMs - mTimeBaseSec * 1000) % mCurrentPullingInterval;
if (mStatsCompanionService != nullptr) {
mStatsCompanionService->setPullingAlarms(nextAlarmTimeMs, mCurrentPullingInterval);
} else {
@@ -195,7 +200,7 @@ void StatsPullerManagerImpl::UnRegisterReceiver(int tagId, wp<PullDataReceiver>
void StatsPullerManagerImpl::OnAlarmFired() {
AutoMutex _l(mReceiversLock);
- uint64_t currentTimeMs = time(nullptr) /60 * 60 * 1000;
+ uint64_t currentTimeMs = getElapsedRealtimeMillis();
vector<pair<int, vector<ReceiverInfo*>>> needToPull =
vector<pair<int, vector<ReceiverInfo*>>>();
diff --git a/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
index 65a1df0eda20..4501b64ad47e 100644
--- a/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
+++ b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
@@ -36,6 +36,7 @@
#include "SubsystemSleepStatePuller.h"
#include "logd/LogEvent.h"
#include "statslog.h"
+#include "stats_log_util.h"
using android::hardware::hidl_vec;
using android::hardware::power::V1_0::IPower;
@@ -84,20 +85,22 @@ bool SubsystemSleepStatePuller::PullInternal(vector<shared_ptr<LogEvent>>* data)
return false;
}
- uint64_t timestamp = time(nullptr) * NS_PER_SEC;
+ int64_t wallClockTimestampNs = getWallClockNs();
+ int64_t elapsedTimestampNs = getElapsedRealtimeNs();
data->clear();
Return<void> ret;
ret = gPowerHalV1_0->getPlatformLowPowerStats(
- [&data, timestamp](hidl_vec<PowerStatePlatformSleepState> states, Status status) {
+ [&data, wallClockTimestampNs, elapsedTimestampNs](hidl_vec<PowerStatePlatformSleepState> states, Status status) {
if (status != Status::SUCCESS) return;
for (size_t i = 0; i < states.size(); i++) {
const PowerStatePlatformSleepState& state = states[i];
- auto statePtr = make_shared<LogEvent>(android::util::SUBSYSTEM_SLEEP_STATE,
- timestamp);
+ auto statePtr = make_shared<LogEvent>(
+ android::util::SUBSYSTEM_SLEEP_STATE,
+ wallClockTimestampNs, elapsedTimestampNs);
statePtr->write(state.name);
statePtr->write("");
statePtr->write(state.totalTransitions);
@@ -109,8 +112,9 @@ bool SubsystemSleepStatePuller::PullInternal(vector<shared_ptr<LogEvent>>* data)
(long long)state.totalTransitions,
state.supportedOnlyInSuspend ? 1 : 0);
for (auto voter : state.voters) {
- auto voterPtr = make_shared<LogEvent>(android::util::SUBSYSTEM_SLEEP_STATE,
- timestamp);
+ auto voterPtr = make_shared<LogEvent>(
+ android::util::SUBSYSTEM_SLEEP_STATE,
+ wallClockTimestampNs, elapsedTimestampNs);
voterPtr->write(state.name);
voterPtr->write(voter.name);
voterPtr->write(voter.totalNumberOfTimesVotedSinceBoot);
@@ -135,7 +139,7 @@ bool SubsystemSleepStatePuller::PullInternal(vector<shared_ptr<LogEvent>>* data)
android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
if (gPowerHal_1_1 != nullptr) {
ret = gPowerHal_1_1->getSubsystemLowPowerStats(
- [&data, timestamp](hidl_vec<PowerStateSubsystem> subsystems, Status status) {
+ [&data, wallClockTimestampNs, elapsedTimestampNs](hidl_vec<PowerStateSubsystem> subsystems, Status status) {
if (status != Status::SUCCESS) return;
if (subsystems.size() > 0) {
@@ -145,7 +149,8 @@ bool SubsystemSleepStatePuller::PullInternal(vector<shared_ptr<LogEvent>>* data)
const PowerStateSubsystemSleepState& state =
subsystem.states[j];
auto subsystemStatePtr = make_shared<LogEvent>(
- android::util::SUBSYSTEM_SLEEP_STATE, timestamp);
+ android::util::SUBSYSTEM_SLEEP_STATE,
+ wallClockTimestampNs, elapsedTimestampNs);
subsystemStatePtr->write(subsystem.name);
subsystemStatePtr->write(state.name);
subsystemStatePtr->write(state.totalTransitions);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 06c5b0049a3b..66cb1d04a4e1 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -45,18 +45,9 @@ const int FIELD_ID_CONFIG_STATS = 3;
const int FIELD_ID_ATOM_STATS = 7;
const int FIELD_ID_UIDMAP_STATS = 8;
const int FIELD_ID_ANOMALY_ALARM_STATS = 9;
-const int FIELD_ID_PULLED_ATOM_STATS = 10;
+// const int FIELD_ID_PULLED_ATOM_STATS = 10; // The proto is written in stats_log_util.cpp
const int FIELD_ID_LOGGER_ERROR_STATS = 11;
-const int FIELD_ID_MATCHER_STATS_NAME = 1;
-const int FIELD_ID_MATCHER_STATS_COUNT = 2;
-
-const int FIELD_ID_CONDITION_STATS_NAME = 1;
-const int FIELD_ID_CONDITION_STATS_COUNT = 2;
-
-const int FIELD_ID_METRIC_STATS_NAME = 1;
-const int FIELD_ID_METRIC_STATS_COUNT = 2;
-
const int FIELD_ID_ATOM_STATS_TAG = 1;
const int FIELD_ID_ATOM_STATS_COUNT = 2;
@@ -80,7 +71,7 @@ std::map<int, long> StatsdStats::kPullerCooldownMap = {
// TODO: add stats for pulled atoms.
StatsdStats::StatsdStats() {
mPushedAtomStats.resize(android::util::kMaxPushedAtomId + 1);
- mStartTimeSec = time(nullptr);
+ mStartTimeSec = getWallClockSec();
}
StatsdStats& StatsdStats::getInstance() {
@@ -99,7 +90,7 @@ void StatsdStats::addToIceBoxLocked(const StatsdStatsReport_ConfigStats& stats)
void StatsdStats::noteConfigReceived(const ConfigKey& key, int metricsCount, int conditionsCount,
int matchersCount, int alertsCount, bool isValid) {
lock_guard<std::mutex> lock(mLock);
- int32_t nowTimeSec = time(nullptr);
+ int32_t nowTimeSec = getWallClockSec();
// If there is an existing config for the same key, icebox the old config.
noteConfigRemovedInternalLocked(key);
@@ -125,7 +116,7 @@ void StatsdStats::noteConfigReceived(const ConfigKey& key, int metricsCount, int
void StatsdStats::noteConfigRemovedInternalLocked(const ConfigKey& key) {
auto it = mConfigStats.find(key);
if (it != mConfigStats.end()) {
- int32_t nowTimeSec = time(nullptr);
+ int32_t nowTimeSec = getWallClockSec();
it->second.set_deletion_time_sec(nowTimeSec);
// Add condition stats, metrics stats, matcher stats, alert stats
addSubStatsToConfigLocked(key, it->second);
@@ -145,7 +136,7 @@ void StatsdStats::noteConfigRemoved(const ConfigKey& key) {
}
void StatsdStats::noteBroadcastSent(const ConfigKey& key) {
- noteBroadcastSent(key, time(nullptr));
+ noteBroadcastSent(key, getWallClockSec());
}
void StatsdStats::noteBroadcastSent(const ConfigKey& key, int32_t timeSec) {
@@ -164,7 +155,7 @@ void StatsdStats::noteBroadcastSent(const ConfigKey& key, int32_t timeSec) {
}
void StatsdStats::noteDataDropped(const ConfigKey& key) {
- noteDataDropped(key, time(nullptr));
+ noteDataDropped(key, getWallClockSec());
}
void StatsdStats::noteDataDropped(const ConfigKey& key, int32_t timeSec) {
@@ -183,7 +174,7 @@ void StatsdStats::noteDataDropped(const ConfigKey& key, int32_t timeSec) {
}
void StatsdStats::noteMetricsReportSent(const ConfigKey& key) {
- noteMetricsReportSent(key, time(nullptr));
+ noteMetricsReportSent(key, getWallClockSec());
}
void StatsdStats::noteMetricsReportSent(const ConfigKey& key, int32_t timeSec) {
@@ -275,10 +266,6 @@ void StatsdStats::notePullFromCache(int pullAtomId) {
void StatsdStats::noteAtomLogged(int atomId, int32_t timeSec) {
lock_guard<std::mutex> lock(mLock);
- if (timeSec < mStartTimeSec) {
- return;
- }
-
if (atomId > android::util::kMaxPushedAtomId) {
ALOGW("not interested in atom %d", atomId);
return;
@@ -293,7 +280,7 @@ void StatsdStats::noteLoggerError(int error) {
if (mLoggerErrors.size() == kMaxLoggerErrors) {
mLoggerErrors.pop_front();
}
- mLoggerErrors.push_back(std::make_pair(time(nullptr), error));
+ mLoggerErrors.push_back(std::make_pair(getWallClockSec(), error));
}
void StatsdStats::reset() {
@@ -303,7 +290,7 @@ void StatsdStats::reset() {
void StatsdStats::resetInternalLocked() {
// Reset the historical data, but keep the active ConfigStats
- mStartTimeSec = time(nullptr);
+ mStartTimeSec = getWallClockSec();
mIceBox.clear();
mConditionStats.clear();
mMetricsStats.clear();
@@ -495,7 +482,7 @@ void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) {
ProtoOutputStream proto;
proto.write(FIELD_TYPE_INT32 | FIELD_ID_BEGIN_TIME, mStartTimeSec);
- proto.write(FIELD_TYPE_INT32 | FIELD_ID_END_TIME, (int32_t)time(nullptr));
+ proto.write(FIELD_TYPE_INT32 | FIELD_ID_END_TIME, (int32_t)getWallClockSec());
for (const auto& configStats : mIceBox) {
const int numBytes = configStats.ByteSize();
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index f254327fcc16..7baa5e57679e 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -42,6 +42,7 @@ public:
const static int kDimensionKeySizeHardLimit = 500;
const static int kMaxConfigCount = 10;
+ const static int kMaxAlertCountPerConfig = 100;
const static int kMaxConditionCountPerConfig = 200;
const static int kMaxMetricCountPerConfig = 300;
const static int kMaxMatcherCountPerConfig = 500;
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 909b74f30508..f07fc66dbcbb 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -33,7 +33,7 @@ using android::util::ProtoOutputStream;
LogEvent::LogEvent(log_msg& msg) {
mContext =
create_android_log_parser(msg.msg() + sizeof(uint32_t), msg.len() - sizeof(uint32_t));
- mTimestampNs = msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec;
+ mLogdTimestampNs = msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec;
mLogUid = msg.entry_v4.uid;
init(mContext);
if (mContext) {
@@ -42,12 +42,24 @@ LogEvent::LogEvent(log_msg& msg) {
}
}
-LogEvent::LogEvent(int32_t tagId, uint64_t timestampNs) {
- mTimestampNs = timestampNs;
+LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs) {
+ mLogdTimestampNs = wallClockTimestampNs;
mTagId = tagId;
mLogUid = 0;
mContext = create_android_logger(1937006964); // the event tag shared by all stats logs
if (mContext) {
+ android_log_write_int64(mContext, elapsedTimestampNs);
+ android_log_write_int32(mContext, tagId);
+ }
+}
+
+LogEvent::LogEvent(int32_t tagId, int64_t timestampNs) {
+ mLogdTimestampNs = timestampNs;
+ mTagId = tagId;
+ mLogUid = 0;
+ mContext = create_android_logger(1937006964); // the event tag shared by all stats logs
+ if (mContext) {
+ android_log_write_int64(mContext, timestampNs);
android_log_write_int32(mContext, tagId);
}
}
@@ -166,18 +178,14 @@ bool LogEvent::write(const AttributionNode& node) {
void LogEvent::init(android_log_context context) {
android_log_list_element elem;
int i = 0;
-
- int seenListStart = 0;
-
- int32_t field = 0;
int depth = -1;
int pos[] = {1, 1, 1};
do {
elem = android_log_read_next(context);
switch ((int)elem.type) {
case EVENT_TYPE_INT:
- // elem at [0] is EVENT_TYPE_LIST, [1] is the tag id.
- if (i == 1) {
+ // elem at [0] is EVENT_TYPE_LIST, [1] is the timestamp, [2] is tag id.
+ if (i == 2) {
mTagId = elem.data.int32;
} else {
if (depth < 0 || depth > 2) {
@@ -214,15 +222,18 @@ void LogEvent::init(android_log_context context) {
} break;
case EVENT_TYPE_LONG: {
- if (depth < 0 || depth > 2) {
- ALOGE("Depth > 2. Not supported!");
- return;
- }
- mValues.push_back(
- FieldValue(Field(mTagId, pos, depth), Value((int64_t)elem.data.int64)));
-
- pos[depth]++;
+ if (i == 1) {
+ mElapsedTimestampNs = elem.data.int64;
+ } else {
+ if (depth < 0 || depth > 2) {
+ ALOGE("Depth > 2. Not supported!");
+ return;
+ }
+ mValues.push_back(
+ FieldValue(Field(mTagId, pos, depth), Value((int64_t)elem.data.int64)));
+ pos[depth]++;
+ }
} break;
case EVENT_TYPE_LIST:
depth++;
@@ -241,10 +252,10 @@ void LogEvent::init(android_log_context context) {
// So that we can later easily match them with Position=Last matchers.
pos[prevDepth]--;
int path = getEncodedField(pos, prevDepth, false);
- for (size_t j = mValues.size() - 1; j >= 0; j--) {
- if (mValues[j].mField.getDepth() >= prevDepth &&
- mValues[j].mField.getPath(prevDepth) == path) {
- mValues[j].mField.decorateLastPos(prevDepth);
+ for (auto it = mValues.rbegin(); it != mValues.rend(); ++it) {
+ if (it->mField.getDepth() >= prevDepth &&
+ it->mField.getPath(prevDepth) == path) {
+ it->mField.decorateLastPos(prevDepth);
} else {
// Safe to break, because the items are in DFS order.
break;
@@ -268,7 +279,9 @@ int64_t LogEvent::GetLong(size_t key, status_t* err) const {
int field = getSimpleField(key);
for (const auto& value : mValues) {
if (value.mField.getField() == field) {
- if (value.mValue.getType() == INT) {
+ if (value.mValue.getType() == LONG) {
+ return value.mValue.long_value;
+ } else if (value.mValue.getType() == INT) {
return value.mValue.int_value;
} else {
*err = BAD_TYPE;
@@ -368,7 +381,7 @@ float LogEvent::GetFloat(size_t key, status_t* err) const {
string LogEvent::ToString() const {
ostringstream result;
- result << "{ " << mTimestampNs << " (" << mTagId << ")";
+ result << "{ " << mLogdTimestampNs << " " << mElapsedTimestampNs << " (" << mTagId << ")";
for (const auto& value : mValues) {
result << StringPrintf("%#x", value.mField.getField());
result << "->";
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 0895daa49ad3..b3084d54d848 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -47,14 +47,18 @@ public:
/**
* Constructs a LogEvent with synthetic data for testing. Must call init() before reading.
*/
- explicit LogEvent(int32_t tagId, uint64_t timestampNs);
+ explicit LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs);
+
+ // For testing. The timestamp is used as both elapsed real time and logd timestamp.
+ explicit LogEvent(int32_t tagId, int64_t timestampNs);
~LogEvent();
/**
* Get the timestamp associated with this event.
*/
- inline uint64_t GetTimestampNs() const { return mTimestampNs; }
+ inline int64_t GetLogdTimestampNs() const { return mLogdTimestampNs; }
+ inline int64_t GetElapsedTimestampNs() const { return mElapsedTimestampNs; }
/**
* Get the tag for this event.
@@ -107,9 +111,18 @@ public:
void init();
/**
- * Set timestamp if the original timestamp is missing.
+ * Set elapsed timestamp if the original timestamp is missing.
*/
- void setTimestampNs(uint64_t timestampNs) {mTimestampNs = timestampNs;}
+ void setElapsedTimestampNs(int64_t timestampNs) {
+ mElapsedTimestampNs = timestampNs;
+ }
+
+ /**
+ * Set the timestamp if the original logd timestamp is missing.
+ */
+ void setLogdWallClockTimestampNs(int64_t timestampNs) {
+ mLogdTimestampNs = timestampNs;
+ }
inline int size() const {
return mValues.size();
@@ -144,7 +157,11 @@ private:
// When the log event is created from log msg, this field is never initiated.
android_log_context mContext = NULL;
- uint64_t mTimestampNs;
+ // The timestamp set by the logd.
+ int64_t mLogdTimestampNs;
+
+ // The elapsed timestamp set by statsd log writer.
+ int64_t mElapsedTimestampNs;
int mTagId;
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index 944764bece8a..461200905a25 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -233,6 +233,11 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher,
(matcher.eq_int() == values[i].mValue.int_value)) {
return true;
}
+ // eq_int covers both int and long.
+ if (values[i].mValue.getType() == LONG &&
+ (matcher.eq_int() == values[i].mValue.long_value)) {
+ return true;
+ }
}
return false;
case FieldValueMatcher::ValueMatcherCase::kLtInt:
@@ -241,6 +246,11 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher,
(values[i].mValue.int_value < matcher.lt_int())) {
return true;
}
+ // lt_int covers both int and long.
+ if (values[i].mValue.getType() == LONG &&
+ (values[i].mValue.long_value < matcher.lt_int())) {
+ return true;
+ }
}
return false;
case FieldValueMatcher::ValueMatcherCase::kGtInt:
@@ -249,6 +259,11 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher,
(values[i].mValue.int_value > matcher.gt_int())) {
return true;
}
+ // gt_int covers both int and long.
+ if (values[i].mValue.getType() == LONG &&
+ (values[i].mValue.long_value > matcher.gt_int())) {
+ return true;
+ }
}
return false;
case FieldValueMatcher::ValueMatcherCase::kLtFloat:
@@ -273,6 +288,11 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher,
(values[i].mValue.int_value <= matcher.lte_int())) {
return true;
}
+ // lte_int covers both int and long.
+ if (values[i].mValue.getType() == LONG &&
+ (values[i].mValue.long_value <= matcher.lte_int())) {
+ return true;
+ }
}
return false;
case FieldValueMatcher::ValueMatcherCase::kGteInt:
@@ -281,6 +301,11 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher,
(values[i].mValue.int_value >= matcher.gte_int())) {
return true;
}
+ // gte_int covers both int and long.
+ if (values[i].mValue.getType() == LONG &&
+ (values[i].mValue.long_value >= matcher.gte_int())) {
+ return true;
+ }
}
return false;
default:
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index bd2674b86a46..af2e362368c3 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -52,8 +52,8 @@ const int FIELD_ID_DIMENSION_IN_WHAT = 1;
const int FIELD_ID_DIMENSION_IN_CONDITION = 2;
const int FIELD_ID_BUCKET_INFO = 3;
// for CountBucketInfo
-const int FIELD_ID_START_BUCKET_NANOS = 1;
-const int FIELD_ID_END_BUCKET_NANOS = 2;
+const int FIELD_ID_START_BUCKET_ELAPSED_NANOS = 1;
+const int FIELD_ID_END_BUCKET_ELAPSED_NANOS = 2;
const int FIELD_ID_COUNT = 3;
CountMetricProducer::CountMetricProducer(const ConfigKey& key, const CountMetric& metric,
@@ -63,7 +63,8 @@ CountMetricProducer::CountMetricProducer(const ConfigKey& key, const CountMetric
: MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard) {
// TODO: evaluate initial conditions. and set mConditionMet.
if (metric.has_bucket()) {
- mBucketSizeNs = TimeUnitToBucketSizeInMillis(metric.bucket()) * 1000000;
+ mBucketSizeNs =
+ TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket()) * 1000000;
} else {
mBucketSizeNs = LLONG_MAX;
}
@@ -107,7 +108,6 @@ void CountMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
if (mPastBuckets.empty()) {
return;
}
-
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
long long protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_COUNT_METRICS);
@@ -132,12 +132,13 @@ void CountMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
}
// Then fill bucket_info (CountBucketInfo).
+
for (const auto& bucket : counter.second) {
long long bucketInfoToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_NANOS,
(long long)bucket.mBucketStartNs);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_NANOS,
(long long)bucket.mBucketEndNs);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_COUNT, (long long)bucket.mCount);
protoOutput->end(bucketInfoToken);
@@ -184,7 +185,7 @@ void CountMetricProducer::onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
const ConditionKey& conditionKey, bool condition,
const LogEvent& event) {
- uint64_t eventTimeNs = event.GetTimestampNs();
+ uint64_t eventTimeNs = event.GetElapsedTimestampNs();
flushIfNeededLocked(eventTimeNs);
if (condition == false) {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 6b321e11edcf..9c65371ba958 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -51,8 +51,8 @@ const int FIELD_ID_DIMENSION_IN_WHAT = 1;
const int FIELD_ID_DIMENSION_IN_CONDITION = 2;
const int FIELD_ID_BUCKET_INFO = 3;
// for DurationBucketInfo
-const int FIELD_ID_START_BUCKET_NANOS = 1;
-const int FIELD_ID_END_BUCKET_NANOS = 2;
+const int FIELD_ID_START_BUCKET_ELAPSED_NANOS = 1;
+const int FIELD_ID_END_BUCKET_ELAPSED_NANOS = 2;
const int FIELD_ID_DURATION = 3;
DurationMetricProducer::DurationMetricProducer(const ConfigKey& key, const DurationMetric& metric,
@@ -72,7 +72,8 @@ DurationMetricProducer::DurationMetricProducer(const ConfigKey& key, const Durat
// them in the base class, because the proto generated CountMetric, and DurationMetric are
// not related. Maybe we should add a template in the future??
if (metric.has_bucket()) {
- mBucketSizeNs = TimeUnitToBucketSizeInMillis(metric.bucket()) * 1000000;
+ mBucketSizeNs =
+ TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket()) * 1000000;
} else {
mBucketSizeNs = LLONG_MAX;
}
@@ -110,12 +111,6 @@ DurationMetricProducer::~DurationMetricProducer() {
sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker(const Alert &alert) {
std::lock_guard<std::mutex> lock(mMutex);
- if (alert.trigger_if_sum_gt() > alert.num_buckets() * mBucketSizeNs) {
- ALOGW("invalid alert: threshold (%f) > possible recordable value (%d x %lld)",
- alert.trigger_if_sum_gt(), alert.num_buckets(),
- (long long)mBucketSizeNs);
- return nullptr;
- }
sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, mConfigKey);
if (anomalyTracker != nullptr) {
mAnomalyTrackers.push_back(anomalyTracker);
@@ -150,10 +145,9 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eve
std::unordered_set<HashableDimensionKey> conditionDimensionsKeySet;
- ConditionState conditionState = mWizard->getMetConditionDimension(
- mConditionTrackerIndex, mDimensionsInCondition, &conditionDimensionsKeySet);
+ mWizard->getMetConditionDimension(mConditionTrackerIndex, mDimensionsInCondition,
+ &conditionDimensionsKeySet);
- bool condition = (conditionState == ConditionState::kTrue);
for (auto& pair : mCurrentSlicedDurationTrackerMap) {
conditionDimensionsKeySet.erase(pair.first.getDimensionKeyInCondition());
}
@@ -221,9 +215,9 @@ void DurationMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
for (const auto& bucket : pair.second) {
long long bucketInfoToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_NANOS,
(long long)bucket.mBucketStartNs);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_NANOS,
(long long)bucket.mBucketEndNs);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DURATION, (long long)bucket.mDuration);
protoOutput->end(bucketInfoToken);
@@ -310,11 +304,11 @@ void DurationMetricProducer::onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
const ConditionKey& conditionKeys, bool condition,
const LogEvent& event) {
- flushIfNeededLocked(event.GetTimestampNs());
+ flushIfNeededLocked(event.GetElapsedTimestampNs());
if (matcherIndex == mStopAllIndex) {
for (auto& pair : mCurrentSlicedDurationTrackerMap) {
- pair.second->noteStopAll(event.GetTimestampNs());
+ pair.second->noteStopAll(event.GetElapsedTimestampNs());
}
return;
}
@@ -333,16 +327,16 @@ void DurationMetricProducer::onMatchedLogEventInternalLocked(
if (values.empty()) {
if (matcherIndex == mStartIndex) {
it->second->noteStart(DEFAULT_DIMENSION_KEY, condition,
- event.GetTimestampNs(), conditionKeys);
+ event.GetElapsedTimestampNs(), conditionKeys);
} else if (matcherIndex == mStopIndex) {
- it->second->noteStop(DEFAULT_DIMENSION_KEY, event.GetTimestampNs(), false);
+ it->second->noteStop(DEFAULT_DIMENSION_KEY, event.GetElapsedTimestampNs(), false);
}
} else {
for (const auto& value : values) {
if (matcherIndex == mStartIndex) {
- it->second->noteStart(value, condition, event.GetTimestampNs(), conditionKeys);
+ it->second->noteStart(value, condition, event.GetElapsedTimestampNs(), conditionKeys);
} else if (matcherIndex == mStopIndex) {
- it->second->noteStop(value, event.GetTimestampNs(), false);
+ it->second->noteStop(value, event.GetElapsedTimestampNs(), false);
}
}
}
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index ed7e44de09c0..2585aa3bdbff 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -19,6 +19,7 @@
#include "EventMetricProducer.h"
#include "stats_util.h"
+#include "stats_log_util.h"
#include <limits.h>
#include <stdlib.h>
@@ -46,8 +47,9 @@ const int FIELD_ID_EVENT_METRICS = 4;
// for EventMetricDataWrapper
const int FIELD_ID_DATA = 1;
// for EventMetricData
-const int FIELD_ID_TIMESTAMP_NANOS = 1;
+const int FIELD_ID_ELAPSED_TIMESTAMP_NANOS = 1;
const int FIELD_ID_ATOMS = 2;
+const int FIELD_ID_WALL_CLOCK_TIMESTAMP_NANOS = 3;
EventMetricProducer::EventMetricProducer(const ConfigKey& key, const EventMetric& metric,
const int conditionIndex,
@@ -127,9 +129,12 @@ void EventMetricProducer::onMatchedLogEventInternalLocked(
long long wrapperToken =
mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_TIMESTAMP_NANOS, (long long)event.GetTimestampNs());
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_ELAPSED_TIMESTAMP_NANOS,
+ (long long)event.GetElapsedTimestampNs());
long long eventToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOMS);
event.ToProto(*mProto);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_WALL_CLOCK_TIMESTAMP_NANOS,
+ (long long)getWallClockNs());
mProto->end(eventToken);
mProto->end(wrapperToken);
}
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index da0cafeca427..0daa506ba42d 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -52,10 +52,10 @@ const int FIELD_ID_DIMENSION_IN_WHAT = 1;
const int FIELD_ID_DIMENSION_IN_CONDITION = 2;
const int FIELD_ID_BUCKET_INFO = 3;
// for GaugeBucketInfo
-const int FIELD_ID_START_BUCKET_NANOS = 1;
-const int FIELD_ID_END_BUCKET_NANOS = 2;
+const int FIELD_ID_START_BUCKET_ELAPSED_NANOS = 1;
+const int FIELD_ID_END_BUCKET_ELAPSED_NANOS = 2;
const int FIELD_ID_ATOM = 3;
-const int FIELD_ID_TIMESTAMP = 4;
+const int FIELD_ID_ELAPSED_ATOM_TIMESTAMP = 4;
GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& metric,
const int conditionIndex,
@@ -69,7 +69,7 @@ GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric
mCurrentSlicedBucketForAnomaly = std::make_shared<DimToValMap>();
int64_t bucketSizeMills = 0;
if (metric.has_bucket()) {
- bucketSizeMills = TimeUnitToBucketSizeInMillis(metric.bucket());
+ bucketSizeMills = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket());
} else {
bucketSizeMills = TimeUnitToBucketSizeInMillis(ONE_HOUR);
}
@@ -161,9 +161,9 @@ void GaugeMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
for (const auto& bucket : pair.second) {
long long bucketInfoToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_NANOS,
(long long)bucket.mBucketStartNs);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_NANOS,
(long long)bucket.mBucketEndNs);
if (!bucket.mGaugeAtoms.empty()) {
@@ -175,8 +175,9 @@ void GaugeMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
protoOutput->end(atomsToken);
for (const auto& atom : bucket.mGaugeAtoms) {
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_TIMESTAMP,
- (long long)atom.mTimestamps);
+ protoOutput->write(
+ FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_ELAPSED_ATOM_TIMESTAMP,
+ (long long)atom.mTimestamps);
}
}
protoOutput->end(bucketInfoToken);
@@ -293,7 +294,7 @@ void GaugeMetricProducer::onMatchedLogEventInternalLocked(
if (condition == false) {
return;
}
- uint64_t eventTimeNs = event.GetTimestampNs();
+ uint64_t eventTimeNs = event.GetElapsedTimestampNs();
mTagId = event.GetTagId();
if (eventTimeNs < mCurrentBucketStartTimeNs) {
VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
@@ -333,7 +334,6 @@ void GaugeMetricProducer::onMatchedLogEventInternalLocked(
}
void GaugeMetricProducer::updateCurrentSlicedBucketForAnomaly() {
- status_t err = NO_ERROR;
for (const auto& slice : *mCurrentSlicedBucket) {
if (slice.second.empty()) {
continue;
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index beb90155f183..f3307dc1d1e3 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -25,7 +25,7 @@ namespace statsd {
using std::map;
void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) {
- uint64_t eventTimeNs = event.GetTimestampNs();
+ uint64_t eventTimeNs = event.GetElapsedTimestampNs();
// this is old event, maybe statsd restarted?
if (eventTimeNs < mStartTimeNs) {
return;
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index e8f8299abd89..8663e5eed7a7 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -123,6 +123,7 @@ public:
return byteSizeLocked();
}
+ /* If alert is valid, adds an AnomalyTracker and returns it. If invalid, returns nullptr. */
virtual sp<AnomalyTracker> addAnomalyTracker(const Alert &alert) {
std::lock_guard<std::mutex> lock(mMutex);
sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, mConfigKey);
@@ -137,6 +138,11 @@ public:
return mBucketSizeNs;
}
+ // Only needed for unit-testing to override guardrail.
+ void setBucketSize(int64_t bucketSize) {
+ mBucketSizeNs = bucketSize;
+ }
+
inline const int64_t& getMetricId() {
return mMetricId;
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index dd6735b6faca..e75b710cc9db 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -26,6 +26,7 @@
#include "matchers/SimpleLogMatchingTracker.h"
#include "metrics_manager_util.h"
#include "stats_util.h"
+#include "stats_log_util.h"
#include <log/logprint.h>
#include <private/android_filesystem_config.h>
@@ -49,9 +50,10 @@ const int FIELD_ID_METRICS = 1;
MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
const long timeBaseSec, sp<UidMap> uidMap)
- : mConfigKey(key), mUidMap(uidMap), mLastReportTimeNs(0) {
+ : mConfigKey(key), mUidMap(uidMap), mLastReportTimeNs(timeBaseSec * NS_PER_SEC) {
mConfigValid =
- initStatsdConfig(key, config, *uidMap, timeBaseSec, mTagIds, mAllAtomMatchers, mAllConditionTrackers,
+ initStatsdConfig(key, config, *uidMap, timeBaseSec, mTagIds, mAllAtomMatchers,
+ mAllConditionTrackers,
mAllMetricProducers, mAllAnomalyTrackers, mConditionToMetricMap,
mTrackerToMetricMap, mTrackerToConditionMap, mNoReportMetricIds);
@@ -90,8 +92,10 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
ALOGE("This config is too big! Reject!");
mConfigValid = false;
}
-
- // TODO: add alert size.
+ if (mAllAnomalyTrackers.size() > StatsdStats::kMaxAlertCountPerConfig) {
+ ALOGE("This config has too many alerts! Reject!");
+ mConfigValid = false;
+ }
// no matter whether this config is valid, log it in the stats.
StatsdStats::getInstance().noteConfigReceived(key, mAllMetricProducers.size(),
mAllConditionTrackers.size(),
@@ -176,7 +180,7 @@ void MetricsManager::onDumpReport(const uint64_t dumpTimeStampNs, ProtoOutputStr
protoOutput->end(token);
}
}
- mLastReportTimeNs = ::android::elapsedRealtimeNano();
+ mLastReportTimeNs = dumpTimeStampNs;
VLOG("=========================Metric Reports End==========================");
}
@@ -186,8 +190,9 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
return;
}
- if (event.GetTagId() == android::util::APP_HOOK) { // Check that app hook fields are valid.
- // TODO: Find a way to make these checks easier to maintain if the app hooks get changed.
+ if (event.GetTagId() == android::util::APP_BREADCRUMB_REPORTED) {
+ // Check that app breadcrumb reported fields are valid.
+ // TODO: Find a way to make these checks easier to maintain.
status_t err = NO_ERROR;
// Uid is 3rd from last field and must match the caller's uid,
@@ -230,7 +235,7 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
}
int tagId = event.GetTagId();
- uint64_t eventTime = event.GetTimestampNs();
+ uint64_t eventTime = event.GetElapsedTimestampNs();
if (mTagIds.find(tagId) == mTagIds.end()) {
// not interesting...
return;
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 45b4ac0cd43a..35fcdc48a08a 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -72,7 +72,7 @@ ValueMetricProducer::ValueMetricProducer(const ConfigKey& key, const ValueMetric
// TODO: valuemetric for pushed events may need unlimited bucket length
int64_t bucketSizeMills = 0;
if (metric.has_bucket()) {
- bucketSizeMills = TimeUnitToBucketSizeInMillis(metric.bucket());
+ bucketSizeMills = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket());
} else {
bucketSizeMills = TimeUnitToBucketSizeInMillis(ONE_HOUR);
}
@@ -219,19 +219,19 @@ void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEven
}
// For scheduled pulled data, the effective event time is snap to the nearest
// bucket boundary to make bucket finalize.
- uint64_t realEventTime = allData.at(0)->GetTimestampNs();
+ uint64_t realEventTime = allData.at(0)->GetElapsedTimestampNs();
uint64_t eventTime = mStartTimeNs +
- ((realEventTime - mStartTimeNs)/mBucketSizeNs) * mBucketSizeNs;
+ ((realEventTime - mStartTimeNs) / mBucketSizeNs) * mBucketSizeNs;
mCondition = false;
for (const auto& data : allData) {
- data->setTimestampNs(eventTime-1);
+ data->setElapsedTimestampNs(eventTime - 1);
onMatchedLogEventLocked(0, *data);
}
mCondition = true;
for (const auto& data : allData) {
- data->setTimestampNs(eventTime);
+ data->setElapsedTimestampNs(eventTime);
onMatchedLogEventLocked(0, *data);
}
}
@@ -261,7 +261,7 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
const ConditionKey& conditionKey, bool condition,
const LogEvent& event) {
- uint64_t eventTimeNs = event.GetTimestampNs();
+ uint64_t eventTimeNs = event.GetElapsedTimestampNs();
if (eventTimeNs < mCurrentBucketStartTimeNs) {
VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
(long long)mCurrentBucketStartTimeNs);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 6701a46acde1..b518f2f841cf 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -62,7 +62,7 @@ public:
// Pretend the pulled data occurs right before the app upgrade event.
mCondition = false;
for (const auto& data : allData) {
- data->setTimestampNs(eventTimeNs - 1);
+ data->setElapsedTimestampNs(eventTimeNs - 1);
onMatchedLogEventLocked(0, *data);
}
@@ -71,7 +71,7 @@ public:
mCondition = true;
for (const auto& data : allData) {
- data->setTimestampNs(eventTimeNs);
+ data->setElapsedTimestampNs(eventTimeNs);
onMatchedLogEventLocked(0, *data);
}
} else { // For pushed value metric, we simply flush and reset the current bucket start.
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index c29876b5eae0..95df5ae6e8bd 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -177,7 +177,6 @@ bool MaxDurationTracker::flushCurrentBucket(
false; // has either a kStarted or kPaused event across bucket boundaries
// meaning we need to carry them over to the new bucket.
for (auto it = mInfos.begin(); it != mInfos.end(); ++it) {
- int64_t finalDuration = it->second.lastDuration;
if (it->second.state == DurationState::kStopped) {
// No need to keep buckets for events that were stopped before.
mInfos.erase(it);
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 769f46dbd7e6..71e5c33b1b88 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -513,10 +513,12 @@ bool initAlerts(const StatsdConfig& config,
const int metricIndex = itr->second;
sp<MetricProducer> metric = allMetricProducers[metricIndex];
sp<AnomalyTracker> anomalyTracker = metric->addAnomalyTracker(alert);
- if (anomalyTracker != nullptr) {
- anomalyTrackerMap.insert(std::make_pair(alert.id(), allAnomalyTrackers.size()));
- allAnomalyTrackers.push_back(anomalyTracker);
+ if (anomalyTracker == nullptr) {
+ // The ALOGW for this invalid alert was already displayed in addAnomalyTracker().
+ return false;
}
+ anomalyTrackerMap.insert(std::make_pair(alert.id(), allAnomalyTrackers.size()));
+ allAnomalyTrackers.push_back(anomalyTracker);
}
for (int i = 0; i < config.subscription_size(); ++i) {
const Subscription& subscription = config.subscription(i);
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 691423e054b2..e322ca4bb1ac 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -16,6 +16,7 @@
#define DEBUG true // STOPSHIP if true
#include "Log.h"
+#include "stats_log_util.h"
#include "guardrail/StatsdStats.h"
#include "packages/UidMap.h"
@@ -82,7 +83,7 @@ int64_t UidMap::getAppVersion(int uid, const string& packageName) const {
void UidMap::updateMap(const vector<int32_t>& uid, const vector<int64_t>& versionCode,
const vector<String16>& packageName) {
- updateMap(time(nullptr) * NS_PER_SEC, uid, versionCode, packageName);
+ updateMap(getElapsedRealtimeNs(), uid, versionCode, packageName);
}
void UidMap::updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
@@ -98,7 +99,7 @@ void UidMap::updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
}
auto snapshot = mOutput.add_snapshots();
- snapshot->set_timestamp_nanos(timestamp);
+ snapshot->set_elapsed_timestamp_nanos(timestamp);
for (size_t j = 0; j < uid.size(); j++) {
auto t = snapshot->add_package_info();
t->set_name(string(String8(packageName[j]).string()));
@@ -125,7 +126,7 @@ void UidMap::updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
}
void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int64_t& versionCode) {
- updateApp(time(nullptr) * NS_PER_SEC, app_16, uid, versionCode);
+ updateApp(getElapsedRealtimeNs(), app_16, uid, versionCode);
}
void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const int32_t& uid,
@@ -137,7 +138,7 @@ void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const i
auto log = mOutput.add_changes();
log->set_deletion(false);
- log->set_timestamp_nanos(timestamp);
+ log->set_elapsed_timestamp_nanos(timestamp);
log->set_app(appName);
log->set_uid(uid);
log->set_version(versionCode);
@@ -194,7 +195,7 @@ void UidMap::ensureBytesUsedBelowLimit() {
}
void UidMap::removeApp(const String16& app_16, const int32_t& uid) {
- removeApp(time(nullptr) * NS_PER_SEC, app_16, uid);
+ removeApp(getElapsedRealtimeNs(), app_16, uid);
}
void UidMap::getListenerListCopyLocked(vector<wp<PackageInfoListener>>* output) {
@@ -218,7 +219,7 @@ void UidMap::removeApp(const int64_t& timestamp, const String16& app_16, const i
auto log = mOutput.add_changes();
log->set_deletion(true);
- log->set_timestamp_nanos(timestamp);
+ log->set_elapsed_timestamp_nanos(timestamp);
log->set_app(app);
log->set_uid(uid);
mBytesUsed += log->ByteSize();
@@ -305,7 +306,7 @@ size_t UidMap::getBytesUsed() const {
}
UidMapping UidMap::getOutput(const ConfigKey& key) {
- return getOutput(time(nullptr) * NS_PER_SEC, key);
+ return getOutput(getElapsedRealtimeNs(), key);
}
UidMapping UidMap::getOutput(const int64_t& timestamp, const ConfigKey& key) {
@@ -321,7 +322,7 @@ UidMapping UidMap::getOutput(const int64_t& timestamp, const ConfigKey& key) {
auto snapshots = mOutput.mutable_snapshots();
auto it_snapshots = snapshots->cbegin();
while (it_snapshots != snapshots->cend()) {
- if (it_snapshots->timestamp_nanos() < cutoff_nanos) {
+ if (it_snapshots->elapsed_timestamp_nanos() < cutoff_nanos) {
// it_snapshots points to the following element after erasing.
it_snapshots = snapshots->erase(it_snapshots);
} else {
@@ -331,7 +332,7 @@ UidMapping UidMap::getOutput(const int64_t& timestamp, const ConfigKey& key) {
auto deltas = mOutput.mutable_changes();
auto it_deltas = deltas->cbegin();
while (it_deltas != deltas->cend()) {
- if (it_deltas->timestamp_nanos() < cutoff_nanos) {
+ if (it_deltas->elapsed_timestamp_nanos() < cutoff_nanos) {
// it_snapshots points to the following element after erasing.
it_deltas = deltas->erase(it_deltas);
} else {
@@ -343,7 +344,7 @@ UidMapping UidMap::getOutput(const int64_t& timestamp, const ConfigKey& key) {
// Produce another snapshot. This results in extra data being uploaded but helps
// ensure we can re-construct the UID->app name, versionCode mapping in server.
auto snapshot = mOutput.add_snapshots();
- snapshot->set_timestamp_nanos(timestamp);
+ snapshot->set_elapsed_timestamp_nanos(timestamp);
for (auto it : mMap) {
auto t = snapshot->add_package_info();
t->set_name(it.second.packageName);
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index b56cffb40806..b427485fd705 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -42,15 +42,17 @@ message DimensionsValueTuple {
}
message EventMetricData {
- optional int64 timestamp_nanos = 1;
+ optional int64 elapsed_timestamp_nanos = 1;
optional Atom atom = 2;
+
+ optional int64 wall_clock_timestamp_sec = 3;
}
message CountBucketInfo {
- optional int64 start_bucket_nanos = 1;
+ optional int64 start_bucket_elapsed_nanos = 1;
- optional int64 end_bucket_nanos = 2;
+ optional int64 end_bucket_elapsed_nanos = 2;
optional int64 count = 3;
}
@@ -64,9 +66,9 @@ message CountMetricData {
}
message DurationBucketInfo {
- optional int64 start_bucket_nanos = 1;
+ optional int64 start_bucket_elapsed_nanos = 1;
- optional int64 end_bucket_nanos = 2;
+ optional int64 end_bucket_elapsed_nanos = 2;
optional int64 duration_nanos = 3;
}
@@ -80,9 +82,9 @@ message DurationMetricData {
}
message ValueBucketInfo {
- optional int64 start_bucket_nanos = 1;
+ optional int64 start_bucket_elapsed_nanos = 1;
- optional int64 end_bucket_nanos = 2;
+ optional int64 end_bucket_elapsed_nanos = 2;
optional int64 value = 3;
}
@@ -102,7 +104,7 @@ message GaugeBucketInfo {
repeated Atom atom = 3;
- repeated int64 timestamp_nanos = 4;
+ repeated int64 elapsed_timestamp_nanos = 4;
}
message GaugeMetricData {
@@ -122,7 +124,7 @@ message UidMapping {
optional int32 uid = 3;
}
- optional int64 timestamp_nanos = 1;
+ optional int64 elapsed_timestamp_nanos = 1;
repeated PackageInfo package_info = 2;
}
@@ -131,7 +133,7 @@ message UidMapping {
message Change {
optional bool deletion = 1;
- optional int64 timestamp_nanos = 2;
+ optional int64 elapsed_timestamp_nanos = 2;
optional string app = 3;
optional int32 uid = 4;
@@ -176,9 +178,9 @@ message ConfigMetricsReport {
optional UidMapping uid_map = 2;
- optional int64 last_report_nanos = 3;
+ optional int64 last_report_elapsed_nanos = 3;
- optional int64 current_report_nanos = 4;
+ optional int64 current_report_elapsed_nanos = 4;
}
message ConfigMetricsReportList {
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index 86c258bd3dfd..30eef4fef166 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -17,9 +17,12 @@
#include "stats_log_util.h"
#include <logd/LogEvent.h>
+#include <private/android_filesystem_config.h>
#include <utils/Log.h>
#include <set>
#include <stack>
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
using android::util::FIELD_COUNT_REPEATED;
using android::util::FIELD_TYPE_BOOL;
@@ -39,15 +42,12 @@ const int DIMENSIONS_VALUE_FIELD = 1;
const int DIMENSIONS_VALUE_VALUE_STR = 2;
const int DIMENSIONS_VALUE_VALUE_INT = 3;
const int DIMENSIONS_VALUE_VALUE_LONG = 4;
-const int DIMENSIONS_VALUE_VALUE_BOOL = 5;
+// const int DIMENSIONS_VALUE_VALUE_BOOL = 5; // logd doesn't have bool data type.
const int DIMENSIONS_VALUE_VALUE_FLOAT = 6;
const int DIMENSIONS_VALUE_VALUE_TUPLE = 7;
const int DIMENSIONS_VALUE_TUPLE_VALUE = 1;
-// for MessageValue Proto
-const int FIELD_ID_FIELD_VALUE_IN_MESSAGE_VALUE_PROTO = 1;
-
// for PulledAtomStats proto
const int FIELD_ID_PULLED_ATOM_STATS = 10;
const int FIELD_ID_PULL_ATOM_ID = 1;
@@ -129,11 +129,6 @@ void writeDimensionToProto(const HashableDimensionKey& dimension, ProtoOutputStr
protoOutput->end(topToken);
}
-// for Field Proto
-const int FIELD_FIELD = 1;
-const int FIELD_POSITION_INDEX = 2;
-const int FIELD_CHILD = 3;
-
// Supported Atoms format
// XYZ_Atom {
// repeated SubMsg field_1 = 1;
@@ -222,6 +217,14 @@ void writeFieldValueTreeToStream(int tagId, const std::vector<FieldValue>& value
protoOutput->end(atomToken);
}
+int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit) {
+ int64_t bucketSizeMillis = TimeUnitToBucketSizeInMillis(unit);
+ if (bucketSizeMillis > 1000 && bucketSizeMillis < 5 * 60 * 1000LL && uid != AID_SHELL) {
+ bucketSizeMillis = 5 * 60 * 1000LL;
+ }
+ return bucketSizeMillis;
+}
+
int64_t TimeUnitToBucketSizeInMillis(TimeUnit unit) {
switch (unit) {
case ONE_MINUTE:
@@ -263,6 +266,30 @@ void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>
protoOutput->end(token);
}
+int64_t getElapsedRealtimeNs() {
+ return ::android::elapsedRealtimeNano();
+}
+
+int64_t getElapsedRealtimeSec() {
+ return ::android::elapsedRealtimeNano() / NS_PER_SEC;
+}
+
+int64_t getElapsedRealtimeMillis() {
+ return ::android::elapsedRealtime();
+}
+
+int64_t getWallClockNs() {
+ return time(nullptr) * NS_PER_SEC;
+}
+
+int64_t getWallClockSec() {
+ return time(nullptr);
+}
+
+int64_t getWallClockMillis() {
+ return time(nullptr) * MS_PER_SEC;
+}
+
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h
index 6583f579648b..6a5123d8c844 100644
--- a/cmds/statsd/src/stats_log_util.h
+++ b/cmds/statsd/src/stats_log_util.h
@@ -32,9 +32,31 @@ void writeFieldValueTreeToStream(int tagId, const std::vector<FieldValue>& value
void writeDimensionToProto(const HashableDimensionKey& dimension,
util::ProtoOutputStream* protoOutput);
+// Convert the TimeUnit enum to the bucket size in millis with a guardrail on
+// bucket size.
+int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit);
+
// Convert the TimeUnit enum to the bucket size in millis.
int64_t TimeUnitToBucketSizeInMillis(TimeUnit unit);
+// Gets the elapsed timestamp in ns.
+int64_t getElapsedRealtimeNs();
+
+// Gets the elapsed timestamp in millis.
+int64_t getElapsedRealtimeMillis();
+
+// Gets the elapsed timestamp in seconds.
+int64_t getElapsedRealtimeSec();
+
+// Gets the wall clock timestamp in ns.
+int64_t getWallClockNs();
+
+// Gets the wall clock timestamp in millis.
+int64_t getWallClockMillis();
+
+// Gets the wall clock timestamp in seconds.
+int64_t getWallClockSec();
+
// Helper function to write PulledAtomStats to ProtoOutputStream
void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>& pair,
util::ProtoOutputStream* protoOutput);
@@ -53,4 +75,4 @@ bool parseProtoOutputStream(util::ProtoOutputStream& protoOutput, T* message) {
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 23bd55616be2..6a1db72b3911 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -20,6 +20,7 @@
#include "android-base/stringprintf.h"
#include "guardrail/StatsdStats.h"
#include "storage/StorageManager.h"
+#include "stats_log_util.h"
#include <android-base/file.h>
#include <dirent.h>
@@ -252,7 +253,7 @@ void StorageManager::trimToFit(const char* path) {
string file_name = getFilePath(path, timestamp, uid, configID);
// Check for timestamp and delete if it's too old.
- long fileAge = time(nullptr) - timestamp;
+ long fileAge = getWallClockSec() - timestamp;
if (fileAge > StatsdStats::kMaxAgeSecond) {
deleteFile(file_name.c_str());
}
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index 01743ef1a45c..022800427b11 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -47,7 +47,7 @@ StatsdConfig CreateStatsdConfig() {
*countMetric->mutable_dimensions_in_what() =
CreateAttributionUidAndTagDimensions(
android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
- countMetric->set_bucket(ONE_MINUTE);
+ countMetric->set_bucket(FIVE_MINUTES);
return config;
}
@@ -163,11 +163,11 @@ TEST(AttributionE2eTest, TestAttributionMatchAndSlice) {
"App1");
EXPECT_EQ(data.bucket_info_size(), 2);
EXPECT_EQ(data.bucket_info(0).count(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).count(), 1);
- EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
data = countMetrics.data(1);
ValidateAttributionUidAndTagDimension(
@@ -175,11 +175,11 @@ TEST(AttributionE2eTest, TestAttributionMatchAndSlice) {
"GMSCoreModule1");
EXPECT_EQ(data.bucket_info_size(), 2);
EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).count(), 1);
- EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
data = countMetrics.data(2);
ValidateAttributionUidAndTagDimension(
@@ -187,8 +187,8 @@ TEST(AttributionE2eTest, TestAttributionMatchAndSlice) {
"GMSCoreModule3");
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + 4 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 4 * bucketSizeNs);
data = countMetrics.data(3);
ValidateAttributionUidAndTagDimension(
@@ -196,8 +196,8 @@ TEST(AttributionE2eTest, TestAttributionMatchAndSlice) {
"GMSCoreModule2");
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
}
#else
@@ -206,4 +206,4 @@ GTEST_LOG_(INFO) << "This test does nothing.\n";
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_test.cpp
index 275b58244e0f..4dffd13bef66 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_test.cpp
@@ -61,7 +61,7 @@ StatsdConfig CreateCountMetricWithNoLinkConfig() {
CreateDimensions(android::util::SCREEN_BRIGHTNESS_CHANGED, {1 /* level */});
*metric->mutable_dimensions_in_condition() = CreateAttributionUidDimensions(
android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
- metric->set_bucket(ONE_MINUTE);
+ metric->set_bucket(FIVE_MINUTES);
return config;
}
@@ -142,8 +142,8 @@ TEST(DimensionInConditionE2eTest, TestCountMetricNoLink) {
auto data = countMetrics.data(0);
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
@@ -153,8 +153,8 @@ TEST(DimensionInConditionE2eTest, TestCountMetricNoLink) {
data = countMetrics.data(1);
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
@@ -165,8 +165,8 @@ TEST(DimensionInConditionE2eTest, TestCountMetricNoLink) {
data = countMetrics.data(2);
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 3);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
@@ -177,11 +177,11 @@ TEST(DimensionInConditionE2eTest, TestCountMetricNoLink) {
data = countMetrics.data(3);
EXPECT_EQ(data.bucket_info_size(), 2);
EXPECT_EQ(data.bucket_info(0).count(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).count(), 1);
- EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
@@ -192,8 +192,8 @@ TEST(DimensionInConditionE2eTest, TestCountMetricNoLink) {
data = countMetrics.data(4);
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
@@ -203,8 +203,8 @@ TEST(DimensionInConditionE2eTest, TestCountMetricNoLink) {
data = countMetrics.data(5);
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
@@ -215,8 +215,8 @@ TEST(DimensionInConditionE2eTest, TestCountMetricNoLink) {
data = countMetrics.data(6);
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
@@ -252,7 +252,7 @@ StatsdConfig CreateCountMetricWithLinkConfig() {
addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
auto metric = config.add_count_metric();
- metric->set_bucket(ONE_MINUTE);
+ metric->set_bucket(FIVE_MINUTES);
metric->set_id(StringToId("AppCrashMetric"));
metric->set_what(appCrashMatcher.id());
metric->set_condition(combinationPredicate->id());
@@ -358,8 +358,8 @@ TEST(DimensionInConditionE2eTest, TestCountMetricWithLink) {
EXPECT_FALSE(data.dimensions_in_condition().has_field());
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
data = countMetrics.data(1);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
@@ -370,8 +370,8 @@ TEST(DimensionInConditionE2eTest, TestCountMetricWithLink) {
android::util::SYNC_STATE_CHANGED, 111, "App1");
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
data = countMetrics.data(2);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
@@ -381,8 +381,8 @@ TEST(DimensionInConditionE2eTest, TestCountMetricWithLink) {
EXPECT_FALSE(data.dimensions_in_condition().has_field());
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
data = countMetrics.data(3);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
@@ -393,11 +393,11 @@ TEST(DimensionInConditionE2eTest, TestCountMetricWithLink) {
android::util::SYNC_STATE_CHANGED, 333, "App2");
EXPECT_EQ(data.bucket_info_size(), 2);
EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).count(), 1);
- EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
data = countMetrics.data(4);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
@@ -407,8 +407,8 @@ TEST(DimensionInConditionE2eTest, TestCountMetricWithLink) {
EXPECT_FALSE(data.dimensions_in_condition().has_field());
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
}
namespace {
@@ -441,7 +441,7 @@ StatsdConfig CreateDurationMetricConfigNoLink(DurationMetric::AggregationType ag
addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
auto metric = config.add_duration_metric();
- metric->set_bucket(ONE_MINUTE);
+ metric->set_bucket(FIVE_MINUTES);
metric->set_id(StringToId("BatterySaverModeDurationMetric"));
metric->set_what(inBatterySaverModePredicate.id());
metric->set_condition(combinationPredicate->id());
@@ -531,11 +531,11 @@ TEST(DimensionInConditionE2eTest, TestDurationMetricNoLink) {
EXPECT_FALSE(data.dimensions_in_condition().has_field());
EXPECT_EQ(data.bucket_info_size(), 2);
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 9);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 30);
- EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
data = metrics.data(1);
EXPECT_FALSE(data.dimensions_in_what().has_field());
@@ -543,11 +543,11 @@ TEST(DimensionInConditionE2eTest, TestDurationMetricNoLink) {
android::util::SYNC_STATE_CHANGED, 111, "App1");
EXPECT_EQ(data.bucket_info_size(), 2);
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201 + bucketSizeNs - 600);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 300);
- EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
data = metrics.data(2);
EXPECT_FALSE(data.dimensions_in_what().has_field());
@@ -555,11 +555,11 @@ TEST(DimensionInConditionE2eTest, TestDurationMetricNoLink) {
android::util::SYNC_STATE_CHANGED, 333, "App2");
EXPECT_EQ(data.bucket_info_size(), 2);
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401 + bucketSizeNs - 600);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
- EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
}
}
@@ -595,7 +595,7 @@ StatsdConfig CreateDurationMetricConfigWithLink(DurationMetric::AggregationType
addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
auto metric = config.add_duration_metric();
- metric->set_bucket(ONE_MINUTE);
+ metric->set_bucket(FIVE_MINUTES);
metric->set_id(StringToId("AppInBackgroundMetric"));
metric->set_what(isInBackgroundPredicate.id());
metric->set_condition(combinationPredicate->id());
@@ -693,8 +693,8 @@ TEST(DimensionInConditionE2eTest, TestDurationMetricWithLink) {
EXPECT_FALSE(data.dimensions_in_condition().has_field());
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 9);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
data = metrics.data(1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
@@ -703,11 +703,11 @@ TEST(DimensionInConditionE2eTest, TestDurationMetricWithLink) {
android::util::SYNC_STATE_CHANGED, 111, "App1");
EXPECT_EQ(data.bucket_info_size(), 2);
EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 201);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
- EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
data = metrics.data(2);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
@@ -716,11 +716,11 @@ TEST(DimensionInConditionE2eTest, TestDurationMetricWithLink) {
android::util::SYNC_STATE_CHANGED, 333, "App2");
EXPECT_EQ(data.bucket_info_size(), 2);
EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 401);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
- EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
}
}
@@ -730,4 +730,4 @@ GTEST_LOG_(INFO) << "This test does nothing.\n";
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp
index 674d810a9ea9..3843e0a3c67d 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp
@@ -53,7 +53,7 @@ StatsdConfig CreateStatsdConfigForPushedEvent() {
fieldMatcher->add_child()->set_field(7); // activity_start_msec(int64)
*gaugeMetric->mutable_dimensions_in_what() =
CreateDimensions(android::util::APP_START_CHANGED, {1 /* uid field */ });
- gaugeMetric->set_bucket(ONE_MINUTE);
+ gaugeMetric->set_bucket(FIVE_MINUTES);
auto links = gaugeMetric->add_links();
links->set_condition(isInBackgroundPredicate.id());
@@ -161,21 +161,21 @@ TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) {
EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().type(), AppStartChanged::HOT);
EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_name(), "activity_name2");
- EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_start_msec(), 102L);
+ EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_start_millis(), 102L);
EXPECT_EQ(data.bucket_info(1).atom_size(), 1);
EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).atom(0).app_start_changed().type(), AppStartChanged::WARM);
EXPECT_EQ(data.bucket_info(1).atom(0).app_start_changed().activity_name(), "activity_name4");
- EXPECT_EQ(data.bucket_info(1).atom(0).app_start_changed().activity_start_msec(), 104L);
+ EXPECT_EQ(data.bucket_info(1).atom(0).app_start_changed().activity_start_millis(), 104L);
EXPECT_EQ(data.bucket_info(2).atom_size(), 1);
EXPECT_EQ(data.bucket_info(2).start_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
EXPECT_EQ(data.bucket_info(2).end_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
EXPECT_EQ(data.bucket_info(2).atom(0).app_start_changed().type(), AppStartChanged::COLD);
EXPECT_EQ(data.bucket_info(2).atom(0).app_start_changed().activity_name(), "activity_name5");
- EXPECT_EQ(data.bucket_info(2).atom(0).app_start_changed().activity_start_msec(), 105L);
+ EXPECT_EQ(data.bucket_info(2).atom(0).app_start_changed().activity_start_millis(), 105L);
data = gaugeMetrics.data(1);
@@ -189,7 +189,7 @@ TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) {
EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().type(), AppStartChanged::COLD);
EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_name(), "activity_name7");
- EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_start_msec(), 201L);
+ EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_start_millis(), 201L);
}
#else
@@ -198,4 +198,4 @@ GTEST_LOG_(INFO) << "This test does nothing.\n";
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index d00518147bfe..1b51780a59bc 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -71,7 +71,7 @@ StatsdConfig CreateStatsdConfig() {
// The metric is dimensioning by uid only.
*countMetric->mutable_dimensions_in_what() =
CreateDimensions(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, {1});
- countMetric->set_bucket(ONE_MINUTE);
+ countMetric->set_bucket(FIVE_MINUTES);
// Links between crash atom and condition of app is in syncing.
auto links = countMetric->add_links();
@@ -337,4 +337,4 @@ GTEST_LOG_(INFO) << "This test does nothing.\n";
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index 3b25694b6517..efdab9822984 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -56,7 +56,7 @@ StatsdConfig CreateStatsdConfig(DurationMetric::AggregationType aggregationType)
*durationMetric->mutable_dimensions_in_what() =
CreateAttributionUidDimensions(
android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
- durationMetric->set_bucket(ONE_MINUTE);
+ durationMetric->set_bucket(FIVE_MINUTES);
return config;
}
@@ -315,9 +315,9 @@ TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration3)
android::util::WAKELOCK_STATE_CHANGED, 111);
// The last wakelock holding spans 4 buckets.
EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 3 * bucketSizeNs);
- EXPECT_EQ((unsigned long long)data.bucket_info(1).start_bucket_nanos(),
+ EXPECT_EQ((unsigned long long)data.bucket_info(1).start_bucket_elapsed_nanos(),
bucketStartTimeNs + 5 * bucketSizeNs);
- EXPECT_EQ((unsigned long long)data.bucket_info(1).end_bucket_nanos(),
+ EXPECT_EQ((unsigned long long)data.bucket_info(1).end_bucket_elapsed_nanos(),
bucketStartTimeNs + 6 * bucketSizeNs);
}
@@ -327,4 +327,4 @@ GTEST_LOG_(INFO) << "This test does nothing.\n";
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
index a1343002405b..bd114439b83c 100644
--- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
+++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -225,7 +225,7 @@ TEST(StatsdStatsTest, TestAtomLog) {
bool dropboxAtomGood = false;
for (const auto& atomStats : report.atom_stats()) {
- if (atomStats.tag() == android::util::SENSOR_STATE_CHANGED && atomStats.count() == 2) {
+ if (atomStats.tag() == android::util::SENSOR_STATE_CHANGED && atomStats.count() == 3) {
sensorAtomGood = true;
}
if (atomStats.tag() == android::util::DROPBOX_ERROR_CHANGED && atomStats.count() == 1) {
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index 1e71b73ca9fa..20ddbe9f0e38 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -48,12 +48,15 @@ TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
metric.set_bucket(ONE_MINUTE);
LogEvent event1(tagId, bucketStartTimeNs + 1);
+ event1.init();
LogEvent event2(tagId, bucketStartTimeNs + 2);
+ event2.init();
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
bucketStartTimeNs);
+ countProducer.setBucketSize(60 * NS_PER_SEC);
// 2 events in bucket 1.
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
@@ -76,6 +79,8 @@ TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
// 1 matched event happens in bucket 2.
LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 2);
+ event3.init();
+
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
countProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
@@ -106,11 +111,15 @@ TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) {
metric.set_condition(StringToId("SCREEN_ON"));
LogEvent event1(1, bucketStartTimeNs + 1);
+ event1.init();
+
LogEvent event2(1, bucketStartTimeNs + 10);
+ event2.init();
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
CountMetricProducer countProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs);
+ countProducer.setBucketSize(60 * NS_PER_SEC);
countProducer.onConditionChanged(true, bucketStartTimeNs);
countProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
@@ -172,6 +181,7 @@ TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard,
bucketStartTimeNs);
+ countProducer.setBucketSize(60 * NS_PER_SEC);
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
countProducer.flushIfNeededLocked(bucketStartTimeNs + 1);
@@ -210,6 +220,8 @@ TEST(CountMetricProducerTest, TestEventWithAppUpgrade) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
bucketStartTimeNs);
+ countProducer.setBucketSize(60 * NS_PER_SEC);
+
sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert);
EXPECT_TRUE(anomalyTracker != nullptr);
@@ -267,6 +279,7 @@ TEST(CountMetricProducerTest, TestEventWithAppUpgradeInNextBucket) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
bucketStartTimeNs);
+ countProducer.setBucketSize(60 * NS_PER_SEC);
// Bucket is flushed yet.
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
@@ -322,16 +335,25 @@ TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
bucketStartTimeNs);
+ countProducer.setBucketSize(60 * NS_PER_SEC);
+
sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert);
int tagId = 1;
LogEvent event1(tagId, bucketStartTimeNs + 1);
+ event1.init();
LogEvent event2(tagId, bucketStartTimeNs + 2);
+ event2.init();
LogEvent event3(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 1);
+ event3.init();
LogEvent event4(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 1);
+ event4.init();
LogEvent event5(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2);
+ event5.init();
LogEvent event6(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 3);
+ event6.init();
LogEvent event7(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC);
+ event7.init();
// Two events in bucket #0.
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
@@ -355,13 +377,13 @@ TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second);
// Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event5.GetTimestampNs() / NS_PER_SEC + refPeriodSec);
+ event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7);
EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second);
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event7.GetTimestampNs() / NS_PER_SEC + refPeriodSec);
+ event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
}
} // namespace statsd
diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
index 23e15f78a96c..79695967a6dd 100644
--- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
@@ -51,12 +51,15 @@ TEST(DurationMetricTrackerTest, TestNoCondition) {
int tagId = 1;
LogEvent event1(tagId, bucketStartTimeNs + 1);
+ event1.init();
LogEvent event2(tagId, bucketStartTimeNs + bucketSizeNs + 2);
+ event2.init();
FieldMatcher dimensions;
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /*no condition*/, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
@@ -86,14 +89,20 @@ TEST(DurationMetricTrackerTest, TestNonSlicedCondition) {
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);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
+
EXPECT_FALSE(durationProducer.mCondition);
EXPECT_FALSE(durationProducer.isConditionSliced());
@@ -143,8 +152,11 @@ TEST(DurationMetricTrackerTest, TestSumDurationWithUpgrade) {
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
- durationProducer.onMatchedLogEvent(1 /* start index*/, LogEvent(tagId, startTimeNs));
+ LogEvent start_event(tagId, startTimeNs);
+ start_event.init();
+ durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
@@ -158,7 +170,9 @@ TEST(DurationMetricTrackerTest, TestSumDurationWithUpgrade) {
EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
// We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
- durationProducer.onMatchedLogEvent(2 /* stop index*/, LogEvent(tagId, endTimeNs));
+ LogEvent end_event(tagId, endTimeNs);
+ end_event.init();
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
EXPECT_EQ(3UL, buckets.size());
EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketStartNs);
@@ -193,8 +207,11 @@ TEST(DurationMetricTrackerTest, TestSumDurationWithUpgradeInFollowingBucket) {
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
- durationProducer.onMatchedLogEvent(1 /* start index*/, LogEvent(tagId, startTimeNs));
+ LogEvent start_event(tagId, startTimeNs);
+ start_event.init();
+ durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
@@ -211,7 +228,9 @@ TEST(DurationMetricTrackerTest, TestSumDurationWithUpgradeInFollowingBucket) {
EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
// We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
- durationProducer.onMatchedLogEvent(2 /* stop index*/, LogEvent(tagId, endTimeNs));
+ LogEvent end_event(tagId, endTimeNs);
+ end_event.init();
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
EXPECT_EQ(3UL, buckets.size());
EXPECT_EQ(eventUpgradeTimeNs, buckets[2].mBucketStartNs);
@@ -242,13 +261,19 @@ TEST(DurationMetricTrackerTest, TestSumDurationAnomalyWithUpgrade) {
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
+
sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert);
EXPECT_TRUE(anomalyTracker != nullptr);
- durationProducer.onMatchedLogEvent(1 /* start index*/, LogEvent(tagId, startTimeNs));
+ LogEvent start_event(tagId, startTimeNs);
+ start_event.init();
+ durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
// We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
- durationProducer.onMatchedLogEvent(2 /* stop index*/, LogEvent(tagId, endTimeNs));
+ LogEvent end_event(tagId, endTimeNs);
+ end_event.init();
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs,
(uint64_t)anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
@@ -275,8 +300,11 @@ TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgrade) {
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
- durationProducer.onMatchedLogEvent(1 /* start index*/, LogEvent(tagId, startTimeNs));
+ LogEvent start_event(tagId, startTimeNs);
+ start_event.init();
+ durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
@@ -285,7 +313,9 @@ TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgrade) {
EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
// We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
- durationProducer.onMatchedLogEvent(2 /* stop index*/, LogEvent(tagId, endTimeNs));
+ LogEvent end_event(tagId, endTimeNs);
+ end_event.init();
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
durationProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
@@ -318,8 +348,11 @@ TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgradeInNextBucket) {
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
- durationProducer.onMatchedLogEvent(1 /* start index*/, LogEvent(tagId, startTimeNs));
+ LogEvent start_event(tagId, startTimeNs);
+ start_event.init();
+ durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
@@ -328,7 +361,9 @@ TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgradeInNextBucket) {
EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
// Stop occurs in the same partial bucket as created for the app upgrade.
- durationProducer.onMatchedLogEvent(2 /* stop index*/, LogEvent(tagId, endTimeNs));
+ LogEvent end_event(tagId, endTimeNs);
+ end_event.init();
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 26f7c2669f15..0eb8ce2603bd 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -67,6 +67,7 @@ TEST(GaugeMetricProducerTest, TestNoCondition) {
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
tagId, bucketStartTimeNs, pullerManager);
+ gaugeProducer.setBucketSize(60 * NS_PER_SEC);
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -144,6 +145,7 @@ TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) {
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-1 /* -1 means no pulling */, bucketStartTimeNs,
pullerManager);
+ gaugeProducer.setBucketSize(60 * NS_PER_SEC);
sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert);
EXPECT_TRUE(anomalyTracker != nullptr);
@@ -225,6 +227,7 @@ TEST(GaugeMetricProducerTest, TestPulledWithUpgrade) {
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
tagId, bucketStartTimeNs, pullerManager);
+ gaugeProducer.setBucketSize(60 * NS_PER_SEC);
vector<shared_ptr<LogEvent>> allData;
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
@@ -292,6 +295,7 @@ TEST(GaugeMetricProducerTest, TestWithCondition) {
GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, tagId,
bucketStartTimeNs, pullerManager);
+ gaugeProducer.setBucketSize(60 * NS_PER_SEC);
gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8);
EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
@@ -350,6 +354,7 @@ TEST(GaugeMetricProducerTest, TestAnomalyDetection) {
gaugeFieldMatcher->add_child()->set_field(2);
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
tagId, bucketStartTimeNs, pullerManager);
+ gaugeProducer.setBucketSize(60 * NS_PER_SEC);
Alert alert;
alert.set_id(101);
@@ -387,7 +392,7 @@ TEST(GaugeMetricProducerTest, TestAnomalyDetection) {
.mFields->begin()
->mValue.int_value);
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event2->GetTimestampNs() / NS_PER_SEC + refPeriodSec);
+ event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
std::shared_ptr<LogEvent> event3 =
std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 10);
@@ -402,7 +407,7 @@ TEST(GaugeMetricProducerTest, TestAnomalyDetection) {
.mFields->begin()
->mValue.int_value);
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event2->GetTimestampNs() / NS_PER_SEC + refPeriodSec);
+ event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
// The event4 does not have the gauge field. Thus the current bucket value is 0.
std::shared_ptr<LogEvent> event4 =
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index 293b1a872a5a..cb731c555e90 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -59,7 +59,6 @@ TEST(OringDurationTrackerTest, TestDurationOverlap) {
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t bucketStartTimeNs = 10000000000;
- uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
uint64_t bucketNum = 0;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t durationTimeNs = 2 * 1000;
@@ -95,7 +94,6 @@ TEST(OringDurationTrackerTest, TestDurationNested) {
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t bucketStartTimeNs = 10000000000;
- uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
uint64_t bucketNum = 0;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
@@ -129,7 +127,6 @@ TEST(OringDurationTrackerTest, TestStopAll) {
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t bucketStartTimeNs = 10000000000;
- uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
uint64_t bucketNum = 0;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
@@ -162,7 +159,6 @@ TEST(OringDurationTrackerTest, TestCrossBucketBoundary) {
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t bucketStartTimeNs = 10000000000;
- uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
uint64_t bucketNum = 0;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t durationTimeNs = 2 * 1000;
@@ -210,7 +206,6 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange) {
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t bucketStartTimeNs = 10000000000;
- uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
uint64_t bucketNum = 0;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t durationTimeNs = 2 * 1000;
@@ -253,7 +248,6 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange2) {
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
uint64_t bucketNum = 0;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t durationTimeNs = 2 * 1000;
@@ -296,7 +290,6 @@ TEST(OringDurationTrackerTest, TestDurationConditionChangeNested) {
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
uint64_t bucketNum = 0;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
@@ -338,7 +331,6 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
- uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
uint64_t bucketNum = 0;
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
@@ -408,7 +400,6 @@ TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
- uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
uint64_t bucketNum = 0;
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
@@ -421,15 +412,15 @@ TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm) {
tracker.noteStop(kEventKey1, eventStartTimeNs + 10, false);
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
EXPECT_TRUE(tracker.mStarted.empty());
- EXPECT_EQ(10LL, tracker.mDuration);
+ EXPECT_EQ(10LL, tracker.mDuration); // 10ns
EXPECT_EQ(0u, tracker.mStarted.size());
tracker.noteStart(kEventKey1, true, eventStartTimeNs + 20, ConditionKey());
EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
- EXPECT_EQ((long long)(51ULL * NS_PER_SEC),
+ EXPECT_EQ((long long)(52ULL * NS_PER_SEC), // (10s + 1s + 1ns + 20ns) - 10ns + 40s, rounded up
(long long)(anomalyTracker->mAlarms.begin()->second->timestampSec * NS_PER_SEC));
- // The alarm is set to fire at 51s, and when it does, an anomaly would be declared. However,
+ // The alarm is set to fire at 52s, and when it does, an anomaly would be declared. However,
// because this is a unit test, the alarm won't actually fire at all. Since the alarm fails
// to fire in time, the anomaly is instead caught when noteStop is called, at around 71s.
tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 25, &buckets);
@@ -460,7 +451,6 @@ TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm) {
ConditionKey conkey;
conkey[StringToId("APP_BACKGROUND")] = kConditionKey1;
uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
- uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 325a372d8056..ce4fa3278493 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -66,6 +66,7 @@ TEST(ValueMetricProducerTest, TestNonDimensionalEvents) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
tagId, bucketStartTimeNs, pullerManager);
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -79,6 +80,8 @@ TEST(ValueMetricProducerTest, TestNonDimensionalEvents) {
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
+
// startUpdated:true tainted:0 sum:0 start:11
EXPECT_EQ(true, curInterval.startUpdated);
EXPECT_EQ(0, curInterval.tainted);
@@ -162,7 +165,7 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs,
pullerManager);
-
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
// has one slice
@@ -215,6 +218,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade) {
make_shared<StrictMock<MockStatsPullerManager>>();
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, -1, bucketStartTimeNs,
pullerManager);
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -269,6 +273,7 @@ TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade) {
}));
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, tagId, bucketStartTimeNs,
pullerManager);
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -311,6 +316,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, -1, bucketStartTimeNs,
pullerManager);
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -357,6 +363,8 @@ TEST(ValueMetricProducerTest, TestAnomalyDetection) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-1 /*not pulled*/, bucketStartTimeNs);
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
+
sp<AnomalyTracker> anomalyTracker = valueProducer.addAnomalyTracker(alert);
@@ -406,16 +414,16 @@ TEST(ValueMetricProducerTest, TestAnomalyDetection) {
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
// Anomaly at event 4 since Value sum == 131 > 130!
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event4->GetTimestampNs() / NS_PER_SEC + refPeriodSec);
+ event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event5);
// Event 5 is within 3 sec refractory period. Thus last alarm timestamp is still event4.
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event4->GetTimestampNs() / NS_PER_SEC + refPeriodSec);
+ event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event6);
// Anomaly at event 6 since Value sum == 160 > 130 and after refractory period.
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event6->GetTimestampNs() / NS_PER_SEC + refPeriodSec);
+ event6->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
}
} // namespace statsd
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index d3a89617e921..b7acef75fafb 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -406,7 +406,7 @@ AttributionNode CreateAttribution(const int& uid, const string& tag) {
void sortLogEventsByTimestamp(std::vector<std::unique_ptr<LogEvent>> *events) {
std::sort(events->begin(), events->end(),
[](const std::unique_ptr<LogEvent>& a, const std::unique_ptr<LogEvent>& b) {
- return a->GetTimestampNs() < b->GetTimestampNs();
+ return a->GetElapsedTimestampNs() < b->GetElapsedTimestampNs();
});
}
diff --git a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
index 03e5fef5d717..b6b16e40a4b2 100644
--- a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
+++ b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
@@ -32,9 +32,9 @@ public class DisplayProtoUtils {
for (StatsLog.ConfigMetricsReport report : reports.getReportsList()) {
sb.append("StatsLogReport size: ").append(report.getMetricsCount()).append("\n");
- sb.append("Last report time:").append(getDateStr(report.getLastReportNanos())).
+ sb.append("Last report time:").append(getDateStr(report.getLastReportElapsedNanos())).
append("\n");
- sb.append("Current report time:").append(getDateStr(report.getCurrentReportNanos())).
+ sb.append("Current report time:").append(getDateStr(report.getCurrentReportElapsedNanos())).
append("\n");
for (StatsLog.StatsLogReport log : report.getMetricsList()) {
sb.append("\n\n");
@@ -109,8 +109,8 @@ public class DisplayProtoUtils {
}
for (StatsLog.DurationBucketInfo info : duration.getBucketInfoList()) {
- sb.append("\t[").append(getDateStr(info.getStartBucketNanos())).append("-")
- .append(getDateStr(info.getEndBucketNanos())).append("] -> ")
+ sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
+ .append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
.append(info.getDurationNanos()).append(" ns\n");
}
}
@@ -121,7 +121,7 @@ public class DisplayProtoUtils {
StatsLog.StatsLogReport.EventMetricDataWrapper eventMetricDataWrapper =
log.getEventMetrics();
for (StatsLog.EventMetricData event : eventMetricDataWrapper.getDataList()) {
- sb.append(getDateStr(event.getTimestampNanos())).append(": ");
+ sb.append(getDateStr(event.getElapsedTimestampNanos())).append(": ");
sb.append(event.getAtom().getPushedCase().toString()).append("\n");
}
}
@@ -141,8 +141,8 @@ public class DisplayProtoUtils {
}
for (StatsLog.CountBucketInfo info : count.getBucketInfoList()) {
- sb.append("\t[").append(getDateStr(info.getStartBucketNanos())).append("-")
- .append(getDateStr(info.getEndBucketNanos())).append("] -> ")
+ sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
+ .append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
.append(info.getCount()).append("\n");
}
}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
index 87b82c261bf1..d55f3f31fd9f 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
@@ -36,9 +36,9 @@ public class DisplayProtoUtils {
int numMetrics = 0;
for (StatsLog.ConfigMetricsReport report : reports.getReportsList()) {
sb.append("StatsLogReport size: ").append(report.getMetricsCount()).append("\n");
- sb.append("Last report time:").append(getDateStr(report.getLastReportNanos())).
+ sb.append("Last report time:").append(getDateStr(report.getLastReportElapsedNanos())).
append("\n");
- sb.append("Current report time:").append(getDateStr(report.getCurrentReportNanos())).
+ sb.append("Current report time:").append(getDateStr(report.getCurrentReportElapsedNanos())).
append("\n");
for (StatsLog.StatsLogReport log : report.getMetricsList()) {
numMetrics++;
@@ -120,8 +120,8 @@ public class DisplayProtoUtils {
}
for (StatsLog.DurationBucketInfo info : duration.getBucketInfoList()) {
- sb.append("\t[").append(getDateStr(info.getStartBucketNanos())).append("-")
- .append(getDateStr(info.getEndBucketNanos())).append("] -> ")
+ sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
+ .append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
.append(info.getDurationNanos()).append(" ns\n");
}
}
@@ -132,7 +132,7 @@ public class DisplayProtoUtils {
StatsLog.StatsLogReport.EventMetricDataWrapper eventMetricDataWrapper =
log.getEventMetrics();
for (StatsLog.EventMetricData event : eventMetricDataWrapper.getDataList()) {
- sb.append(getDateStr(event.getTimestampNanos())).append(": ");
+ sb.append(getDateStr(event.getElapsedTimestampNanos())).append(": ");
sb.append(event.getAtom().getPushedCase().toString()).append("\n");
}
}
@@ -152,8 +152,8 @@ public class DisplayProtoUtils {
}
for (StatsLog.CountBucketInfo info : count.getBucketInfoList()) {
- sb.append("\t[").append(getDateStr(info.getStartBucketNanos())).append("-")
- .append(getDateStr(info.getEndBucketNanos())).append("] -> ")
+ sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
+ .append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
.append(info.getCount()).append("\n");
}
}
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 44f43a254361..a7d07e341728 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -21,6 +21,7 @@ Landroid/app/ActivityManager;->IActivityManagerSingleton:Landroid/util/Singleton
Landroid/app/ActivityManager;->isLowRamDeviceStatic()Z
Landroid/app/ActivityManager;->isUserRunning(I)Z
Landroid/app/ActivityManager;->mContext:Landroid/content/Context;
+Landroid/app/ActivityManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/app/IActivityManager;
Landroid/app/ActivityManagerNative;->getDefault()Landroid/app/IActivityManager;
Landroid/app/ActivityManager;->PROCESS_STATE_TOP:I
Landroid/app/ActivityManager$RecentTaskInfo;->firstActiveTime:J
@@ -40,6 +41,7 @@ Landroid/app/Activity;->mToken:Landroid/os/IBinder;
Landroid/app/Activity;->mWindow:Landroid/view/Window;
Landroid/app/Activity;->mWindowManager:Landroid/view/WindowManager;
Landroid/app/Activity;->setDisablePreviewScreenshots(Z)V
+Landroid/app/Activity;->setPersistent(Z)V
Landroid/app/ActivityThread$ActivityClientRecord;->activityInfo:Landroid/content/pm/ActivityInfo;
Landroid/app/ActivityThread$ActivityClientRecord;->activity:Landroid/app/Activity;
Landroid/app/ActivityThread$ActivityClientRecord;->compatInfo:Landroid/content/res/CompatibilityInfo;
@@ -52,6 +54,7 @@ Landroid/app/ActivityThread$ActivityClientRecord;->token:Landroid/os/IBinder;
Landroid/app/ActivityThread$AppBindData;->appInfo:Landroid/content/pm/ApplicationInfo;
Landroid/app/ActivityThread$AppBindData;->info:Landroid/app/LoadedApk;
Landroid/app/ActivityThread$AppBindData;->instrumentationArgs:Landroid/os/Bundle;
+Landroid/app/ActivityThread$AppBindData;->processName:Ljava/lang/String;
Landroid/app/ActivityThread$AppBindData;->providers:Ljava/util/List;
Landroid/app/ActivityThread$BindServiceData;->intent:Landroid/content/Intent;
Landroid/app/ActivityThread$BindServiceData;->token:Landroid/os/IBinder;
@@ -87,15 +90,20 @@ Landroid/app/ActivityThread;->installProvider(Landroid/content/Context;Landroid/
Landroid/app/ActivityThread;->mActivities:Landroid/util/ArrayMap;
Landroid/app/ActivityThread;->mAllApplications:Ljava/util/ArrayList;
Landroid/app/ActivityThread;->mBoundApplication:Landroid/app/ActivityThread$AppBindData;
+Landroid/app/ActivityThread;->mDensityCompatMode:Z
Landroid/app/ActivityThread;->mH:Landroid/app/ActivityThread$H;
Landroid/app/ActivityThread;->mInitialApplication:Landroid/app/Application;
Landroid/app/ActivityThread;->mInstrumentation:Landroid/app/Instrumentation;
+Landroid/app/ActivityThread;->mLocalProvidersByName:Landroid/util/ArrayMap;
Landroid/app/ActivityThread;->mNumVisibleActivities:I
Landroid/app/ActivityThread;->mPackages:Landroid/util/ArrayMap;
Landroid/app/ActivityThread;->mProviderMap:Landroid/util/ArrayMap;
Landroid/app/ActivityThread;->mServices:Landroid/util/ArrayMap;
+Landroid/app/ActivityThread;->performNewIntents(Landroid/os/IBinder;Ljava/util/List;Z)V
Landroid/app/ActivityThread;->performStopActivity(Landroid/os/IBinder;ZLjava/lang/String;)V
+Landroid/app/ActivityThread$ProviderClientRecord;->mHolder:Landroid/app/ContentProviderHolder;
Landroid/app/ActivityThread$ProviderClientRecord;->mLocalProvider:Landroid/content/ContentProvider;
+Landroid/app/ActivityThread$ProviderClientRecord;->mProvider:Landroid/content/IContentProvider;
Landroid/app/ActivityThread$ReceiverData;->compatInfo:Landroid/content/res/CompatibilityInfo;
Landroid/app/ActivityThread$ReceiverData;->info:Landroid/content/pm/ActivityInfo;
Landroid/app/ActivityThread$ReceiverData;->intent:Landroid/content/Intent;
@@ -104,6 +112,7 @@ Landroid/app/ActivityThread;->sendActivityResult(Landroid/os/IBinder;Ljava/lang/
Landroid/app/ActivityThread$ServiceArgsData;->args:Landroid/content/Intent;
Landroid/app/ActivityThread$ServiceArgsData;->token:Landroid/os/IBinder;
Landroid/app/ActivityThread;->sPackageManager:Landroid/content/pm/IPackageManager;
+Landroid/app/ActivityThread;->startActivityNow(Landroid/app/Activity;Ljava/lang/String;Landroid/content/Intent;Landroid/content/pm/ActivityInfo;Landroid/os/IBinder;Landroid/os/Bundle;Landroid/app/Activity$NonConfigurationInstances;)Landroid/app/Activity;
Landroid/app/admin/DevicePolicyManager;->getDeviceOwnerComponentOnAnyUser()Landroid/content/ComponentName;
Landroid/app/admin/DevicePolicyManager;->getDeviceOwner()Ljava/lang/String;
Landroid/app/admin/DevicePolicyManager;->getProfileOwner()Landroid/content/ComponentName;
@@ -121,6 +130,7 @@ Landroid/app/AlarmManager;->FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED:I
Landroid/app/AlarmManager;->FLAG_IDLE_UNTIL:I
Landroid/app/AlarmManager;->FLAG_STANDALONE:I
Landroid/app/AlarmManager;->FLAG_WAKE_FROM_IDLE:I
+Landroid/app/AlarmManager;->mService:Landroid/app/IAlarmManager;
Landroid/app/AlarmManager;->set(IJJJLandroid/app/AlarmManager$OnAlarmListener;Landroid/os/Handler;Landroid/os/WorkSource;)V
Landroid/app/AlarmManager;->set(IJJJLandroid/app/PendingIntent;Landroid/os/WorkSource;)V
Landroid/app/AlarmManager;->WINDOW_EXACT:J
@@ -142,6 +152,7 @@ Landroid/app/ApplicationLoaders;->getDefault()Landroid/app/ApplicationLoaders;
Landroid/app/ApplicationLoaders;->mLoaders:Landroid/util/ArrayMap;
Landroid/app/Application;->mComponentCallbacks:Ljava/util/ArrayList;
Landroid/app/Application;->mLoadedApk:Landroid/app/LoadedApk;
+Landroid/app/ApplicationPackageManager;->configurationChanged()V
Landroid/app/ApplicationPackageManager;->deletePackage(Ljava/lang/String;Landroid/content/pm/IPackageDeleteObserver;I)V
Landroid/app/ApplicationPackageManager;->getPackageSizeInfoAsUser(Ljava/lang/String;ILandroid/content/pm/IPackageStatsObserver;)V
Landroid/app/ApplicationPackageManager;-><init>(Landroid/app/ContextImpl;Landroid/content/pm/IPackageManager;)V
@@ -199,11 +210,15 @@ Landroid/app/backup/RestoreSession;->getAvailableRestoreSets(Landroid/app/backup
Landroid/app/backup/RestoreSession;->restoreAll(JLandroid/app/backup/RestoreObserver;)I
Landroid/app/backup/RestoreSet;-><init>(Ljava/lang/String;Ljava/lang/String;J)V
Landroid/app/backup/SelectBackupTransportCallback;-><init>()V
+Landroid/app/ContentProviderHolder;->info:Landroid/content/pm/ProviderInfo;
+Landroid/app/ContentProviderHolder;-><init>(Landroid/content/pm/ProviderInfo;)V
Landroid/app/ContentProviderHolder;->provider:Landroid/content/IContentProvider;
Landroid/app/ContextImpl;->createActivityContext(Landroid/app/ActivityThread;Landroid/app/LoadedApk;Landroid/content/pm/ActivityInfo;Landroid/os/IBinder;ILandroid/content/res/Configuration;)Landroid/app/ContextImpl;
Landroid/app/ContextImpl;->getActivityToken()Landroid/os/IBinder;
Landroid/app/ContextImpl;->getDisplay()Landroid/view/Display;
Landroid/app/ContextImpl;->getPreferencesDir()Ljava/io/File;
+Landroid/app/ContextImpl;->getReceiverRestrictedContext()Landroid/content/Context;
+Landroid/app/ContextImpl;->mBasePackageName:Ljava/lang/String;
Landroid/app/ContextImpl;->mContentResolver:Landroid/app/ContextImpl$ApplicationContentResolver;
Landroid/app/ContextImpl;->mMainThread:Landroid/app/ActivityThread;
Landroid/app/ContextImpl;->mOpPackageName:Ljava/lang/String;
@@ -215,6 +230,7 @@ Landroid/app/ContextImpl;->mServiceCache:[Ljava/lang/Object;
Landroid/app/ContextImpl;->mTheme:Landroid/content/res/Resources$Theme;
Landroid/app/ContextImpl;->scheduleFinalCleanup(Ljava/lang/String;Ljava/lang/String;)V
Landroid/app/ContextImpl;->setOuterContext(Landroid/content/Context;)V
+Landroid/app/ContextImpl;->sSharedPrefsCache:Landroid/util/ArrayMap;
Landroid/app/DatePickerDialog;->mDatePicker:Landroid/widget/DatePicker;
Landroid/app/Dialog;->CANCEL:I
Landroid/app/Dialog;->dismissDialog()V
@@ -226,16 +242,23 @@ Landroid/app/Dialog;->mShowMessage:Landroid/os/Message;
Landroid/app/DownloadManager$Request;->mUri:Landroid/net/Uri;
Landroid/app/FragmentManagerImpl;->mAdded:Ljava/util/ArrayList;
Landroid/app/Fragment;->mChildFragmentManager:Landroid/app/FragmentManagerImpl;
+Landroid/app/IActivityManager;->bindService(Landroid/app/IApplicationThread;Landroid/os/IBinder;Landroid/content/Intent;Ljava/lang/String;Landroid/app/IServiceConnection;ILjava/lang/String;I)I
+Landroid/app/IActivityManager;->finishActivity(Landroid/os/IBinder;ILandroid/content/Intent;I)Z
+Landroid/app/IActivityManager;->finishReceiver(Landroid/os/IBinder;ILjava/lang/String;Landroid/os/Bundle;ZI)V
Landroid/app/IActivityManager;->forceStopPackage(Ljava/lang/String;I)V
Landroid/app/IActivityManager;->getLaunchedFromPackage(Landroid/os/IBinder;)Ljava/lang/String;
Landroid/app/IActivityManager;->getTaskForActivity(Landroid/os/IBinder;Z)I
+Landroid/app/IActivityManager;->moveTaskToFront(IILandroid/os/Bundle;)V
+Landroid/app/IActivityManager;->publishContentProviders(Landroid/app/IApplicationThread;Ljava/util/List;)V
Landroid/app/IActivityManager;->resumeAppSwitches()V
Landroid/app/IActivityManager;->setRequestedOrientation(Landroid/os/IBinder;I)V
+Landroid/app/IActivityManager;->setTaskResizeable(II)V
Landroid/app/IActivityManager$Stub$Proxy;->getConfiguration()Landroid/content/res/Configuration;
Landroid/app/IActivityManager$Stub$Proxy;->getLaunchedFromUid(Landroid/os/IBinder;)I
Landroid/app/IActivityManager$Stub$Proxy;->getProcessPss([I)[J
Landroid/app/IActivityManager$Stub$Proxy;->isAppForeground(I)Z
Landroid/app/IActivityManager$Stub$Proxy;->mRemote:Landroid/os/IBinder;
+Landroid/app/IActivityManager;->unbindService(Landroid/app/IServiceConnection;)Z
Landroid/app/IAlarmManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/app/IAlarmManager$Stub;->TRANSACTION_remove:I
Landroid/app/IAlarmManager$Stub;->TRANSACTION_set:I
@@ -255,6 +278,8 @@ Landroid/app/IUiModeManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/app/IWallpaperManager;->getWallpaper(Ljava/lang/String;Landroid/app/IWallpaperManagerCallback;ILandroid/os/Bundle;I)Landroid/os/ParcelFileDescriptor;
Landroid/app/job/IJobScheduler$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/job/IJobScheduler;
Landroid/app/job/IJobScheduler$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Landroid/app/LoadedApk;->getClassLoader()Ljava/lang/ClassLoader;
+Landroid/app/LoadedApk;->getDataDirFile()Ljava/io/File;
Landroid/app/LoadedApk;->mActivityThread:Landroid/app/ActivityThread;
Landroid/app/LoadedApk;->makeApplication(ZLandroid/app/Instrumentation;)Landroid/app/Application;
Landroid/app/LoadedApk;->mAppDir:Ljava/lang/String;
@@ -262,7 +287,9 @@ Landroid/app/LoadedApk;->mApplicationInfo:Landroid/content/pm/ApplicationInfo;
Landroid/app/LoadedApk;->mApplication:Landroid/app/Application;
Landroid/app/LoadedApk;->mBaseClassLoader:Ljava/lang/ClassLoader;
Landroid/app/LoadedApk;->mClassLoader:Ljava/lang/ClassLoader;
+Landroid/app/LoadedApk;->mDataDirFile:Ljava/io/File;
Landroid/app/LoadedApk;->mDataDir:Ljava/lang/String;
+Landroid/app/LoadedApk;->mDisplayAdjustments:Landroid/view/DisplayAdjustments;
Landroid/app/LoadedApk;->mPackageName:Ljava/lang/String;
Landroid/app/LoadedApk;->mReceivers:Landroid/util/ArrayMap;
Landroid/app/LoadedApk;->mResDir:Ljava/lang/String;
@@ -275,6 +302,7 @@ Landroid/app/NativeActivity;->setWindowFlags(II)V
Landroid/app/NativeActivity;->setWindowFormat(I)V
Landroid/app/NativeActivity;->showIme(I)V
Landroid/app/Notification$Builder;->mActions:Ljava/util/ArrayList;
+Landroid/app/Notification$Builder;->setChannel(Ljava/lang/String;)Landroid/app/Notification$Builder;
Landroid/app/Notification;->EXTRA_SUBSTITUTE_APP_NAME:Ljava/lang/String;
Landroid/app/Notification;->isGroupSummary()Z
Landroid/app/NotificationManager;->getService()Landroid/app/INotificationManager;
@@ -309,6 +337,7 @@ Landroid/app/StatusBarManager;->disable(I)V
Landroid/app/StatusBarManager;->expandNotificationsPanel()V
Landroid/app/StatusBarManager;->expandSettingsPanel(Ljava/lang/String;)V
Landroid/app/StatusBarManager;->expandSettingsPanel()V
+Landroid/app/StatusBarManager;->getService()Lcom/android/internal/statusbar/IStatusBarService;
Landroid/app/TimePickerDialog;->mTimePicker:Landroid/widget/TimePicker;
Landroid/app/trust/ITrustManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/app/usage/UsageStatsManager;->getAppStandbyBuckets()Ljava/util/Map;
@@ -360,12 +389,17 @@ Landroid/bluetooth/le/ScanSettings$Builder;->setScanResultType(I)Landroid/blueto
Landroid/content/AsyncTaskLoader;->mExecutor:Ljava/util/concurrent/Executor;
Landroid/content/BroadcastReceiver$PendingResult;-><init>(ILjava/lang/String;Landroid/os/Bundle;IZZLandroid/os/IBinder;II)V
Landroid/content/BroadcastReceiver;->setPendingResult(Landroid/content/BroadcastReceiver$PendingResult;)V
+Landroid/content/ContentProviderClient;->mContentProvider:Landroid/content/IContentProvider;
+Landroid/content/ContentProviderClient;->mPackageName:Ljava/lang/String;
Landroid/content/ContentProvider;->mContext:Landroid/content/Context;
Landroid/content/ContentProvider;->mPathPermissions:[Landroid/content/pm/PathPermission;
Landroid/content/ContentProvider;->mReadPermission:Ljava/lang/String;
Landroid/content/ContentProvider;->mWritePermission:Ljava/lang/String;
Landroid/content/ContentProviderOperation;->mSelection:Ljava/lang/String;
Landroid/content/ContentProviderOperation;->mType:I
+Landroid/content/ContentProviderOperation;->TYPE_DELETE:I
+Landroid/content/ContentProviderOperation;->TYPE_INSERT:I
+Landroid/content/ContentProviderOperation;->TYPE_UPDATE:I
Landroid/content/ContentResolver;->acquireProvider(Landroid/net/Uri;)Landroid/content/IContentProvider;
Landroid/content/ContentResolver;->getContentService()Landroid/content/IContentService;
Landroid/content/ContentResolver;->getSyncStatus(Landroid/accounts/Account;Ljava/lang/String;)Landroid/content/SyncStatusInfo;
@@ -390,9 +424,11 @@ Landroid/content/ContextWrapper;->mBase:Landroid/content/Context;
Landroid/content/CursorLoader;->mCancellationSignal:Landroid/os/CancellationSignal;
Landroid/content/CursorLoader;->mObserver:Landroid/content/Loader$ForceLoadContentObserver;
Landroid/content/IClipboard$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IClipboard;
+Landroid/content/IContentProvider;->call(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/os/Bundle;)Landroid/os/Bundle;
Landroid/content/IContentService;->cancelSync(Landroid/accounts/Account;Ljava/lang/String;Landroid/content/ComponentName;)V
Landroid/content/IContentService;->getMasterSyncAutomatically()Z
Landroid/content/IContentService;->setMasterSyncAutomatically(Z)V
+Landroid/content/IContentService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IContentService;
Landroid/content/IContentService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/Intent;->ACTION_ALARM_CHANGED:Ljava/lang/String;
Landroid/content/IntentFilter;->mActions:Ljava/util/ArrayList;
@@ -425,6 +461,7 @@ Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackageInfo(Ljava/lang/Strin
Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackagesForUid(I)[Ljava/lang/String;
Landroid/content/pm/IPackageManager$Stub$Proxy;->getSystemSharedLibraryNames()[Ljava/lang/String;
Landroid/content/pm/IPackageStatsObserver$Stub;-><init>()V
+Landroid/content/pm/LauncherActivityInfo;->mActivityInfo:Landroid/content/pm/ActivityInfo;
Landroid/content/pm/LauncherApps;->mPm:Landroid/content/pm/PackageManager;
Landroid/content/pm/LauncherApps;->startShortcut(Ljava/lang/String;Ljava/lang/String;Landroid/graphics/Rect;Landroid/os/Bundle;I)V
Landroid/content/pm/PackageInstaller$SessionParams;->setAllocateAggressive(Z)V
@@ -566,6 +603,7 @@ Landroid/content/res/XmlBlock$Parser;->mParseState:J
Landroid/content/SyncStatusInfo;->lastSuccessTime:J
Landroid/database/AbstractCursor;->mExtras:Landroid/os/Bundle;
Landroid/database/AbstractCursor;->mNotifyUri:Landroid/net/Uri;
+Landroid/database/AbstractCursor;->mRowIdColumnIndex:I
Landroid/database/CursorWindow;->mWindowPtr:J
Landroid/database/CursorWindow;->sCursorWindowSize:I
Landroid/database/CursorWindow;->sWindowToPidMap:Landroid/util/LongSparseArray;
@@ -743,6 +781,38 @@ Landroid/hardware/SystemSensorManager$BaseEventQueue;->dispatchSensorEvent(I[FIJ
Landroid/hardware/usb/UsbDeviceConnection;->mNativeContext:J
Landroid/hardware/usb/UsbManager;->setCurrentFunction(Ljava/lang/String;Z)V
Landroid/hardware/usb/UsbRequest;->mNativeContext:J
+Landroid/icu/impl/number/DecimalFormatProperties;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/impl/number/DecimalFormatProperties;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/impl/TimeZoneGenericNames;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DateFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DateFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DateIntervalFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DecimalFormat_ICU58_Android;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DecimalFormat_ICU58_Android;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/DecimalFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DecimalFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DecimalFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/MessageFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/MessageFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/NumberFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/NumberFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/PluralFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/PluralRules$FixedDecimal;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/PluralRules$FixedDecimal;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/PluralRules;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/PluralRules;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/RuleBasedNumberFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/RuleBasedNumberFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/SelectFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/SimpleDateFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/SimpleDateFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/TimeZoneFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/TimeZoneFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/util/Calendar;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/util/Calendar;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/util/ChineseCalendar;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/util/IslamicCalendar;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/util/SimpleTimeZone;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/location/CountryDetector;->detectCountry()Landroid/location/Country;
Landroid/location/Country;->getCountryIso()Ljava/lang/String;
Landroid/location/Country;->getSource()I
@@ -860,6 +930,7 @@ Landroid/media/MediaFile;->getFileType(Ljava/lang/String;)Landroid/media/MediaFi
Landroid/media/MediaFile;->getMimeTypeForFile(Ljava/lang/String;)Ljava/lang/String;
Landroid/media/MediaFile;-><init>()V
Landroid/media/MediaFile;->isAudioFileType(I)Z
+Landroid/media/MediaFile;->isImageFileType(I)Z
Landroid/media/MediaFile;->isVideoFileType(I)Z
Landroid/media/MediaFile;->LAST_AUDIO_FILE_TYPE:I
Landroid/media/MediaFile$MediaFileType;->fileType:I
@@ -1063,6 +1134,7 @@ Landroid/net/wifi/WifiConfiguration;->validatedInternetAccess:Z
Landroid/net/wifi/WifiEnterpriseConfig;->getCaCertificateAlias()Ljava/lang/String;
Landroid/net/wifi/WifiEnterpriseConfig;->getClientCertificateAlias()Ljava/lang/String;
Landroid/net/wifi/WifiInfo;->getMeteredHint()Z
+Landroid/net/wifi/WifiInfo;->mMacAddress:Ljava/lang/String;
Landroid/net/wifi/WifiManager;->cancelLocalOnlyHotspotRequest()V
Landroid/net/wifi/WifiManager;->connect(ILandroid/net/wifi/WifiManager$ActionListener;)V
Landroid/net/wifi/WifiManager;->connect(Landroid/net/wifi/WifiConfiguration;Landroid/net/wifi/WifiManager$ActionListener;)V
@@ -1186,6 +1258,7 @@ Landroid/os/IPowerManager;->userActivity(JII)V
Landroid/os/IServiceManager;->getService(Ljava/lang/String;)Landroid/os/IBinder;
Landroid/os/IUserManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/os/Looper;->mQueue:Landroid/os/MessageQueue;
+Landroid/os/Looper;->setTraceTag(J)V
Landroid/os/Looper;->sThreadLocal:Ljava/lang/ThreadLocal;
Landroid/os/MemoryFile;->getFileDescriptor()Ljava/io/FileDescriptor;
Landroid/os/Message;->callback:Ljava/lang/Runnable;
@@ -1199,7 +1272,9 @@ Landroid/os/MessageQueue;->mPtr:J
Landroid/os/MessageQueue;->mQuitAllowed:Z
Landroid/os/MessageQueue;->nativePollOnce(JI)V
Landroid/os/MessageQueue;->next()Landroid/os/Message;
+Landroid/os/Message;->recycleUnchecked()V
Landroid/os/Message;->target:Landroid/os/Handler;
+Landroid/os/Message;->when:J
Landroid/os/ParcelFileDescriptor;-><init>(Ljava/io/FileDescriptor;)V
Landroid/os/Parcel;->mNativePtr:J
Landroid/os/Parcel$ReadWriteHelper;-><init>()V
@@ -1378,16 +1453,24 @@ Landroid/provider/Browser;->deleteFromHistory(Landroid/content/ContentResolver;L
Landroid/provider/Browser;->getVisitedHistory(Landroid/content/ContentResolver;)[Ljava/lang/String;
Landroid/provider/Browser;->sendString(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)V
Landroid/provider/Settings$ContentProviderHolder;->mContentProvider:Landroid/content/IContentProvider;
+Landroid/provider/Settings$Global;->ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED:Ljava/lang/String;
Landroid/provider/Settings$Global;->OTA_DISABLE_AUTOMATIC_UPDATE:Ljava/lang/String;
Landroid/provider/Settings$Global;->PACKAGE_VERIFIER_ENABLE:Ljava/lang/String;
Landroid/provider/Settings$Global;->sNameValueCache:Landroid/provider/Settings$NameValueCache;
Landroid/provider/Settings$NameValueCache;->mProviderHolder:Landroid/provider/Settings$ContentProviderHolder;
+Landroid/provider/Settings$Secure;->ACCESSIBILITY_AUTOCLICK_ENABLED:Ljava/lang/String;
+Landroid/provider/Settings$Secure;->ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:Ljava/lang/String;
Landroid/provider/Settings$Secure;->ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED:Ljava/lang/String;
+Landroid/provider/Settings$Secure;->ACCESSIBILITY_LARGE_POINTER_ICON:Ljava/lang/String;
+Landroid/provider/Settings$Secure;->INCALL_POWER_BUTTON_BEHAVIOR:Ljava/lang/String;
+Landroid/provider/Settings$Secure;->LONG_PRESS_TIMEOUT:Ljava/lang/String;
Landroid/provider/Settings$Secure;->PACKAGE_VERIFIER_USER_CONSENT:Ljava/lang/String;
Landroid/provider/Settings$Secure;->sNameValueCache:Landroid/provider/Settings$NameValueCache;
Landroid/provider/Settings$Secure;->USER_SETUP_COMPLETE:Ljava/lang/String;
Landroid/provider/Settings$System;->AIRPLANE_MODE_TOGGLEABLE_RADIOS:Ljava/lang/String;
Landroid/provider/Settings$System;->getStringForUser(Landroid/content/ContentResolver;Ljava/lang/String;I)Ljava/lang/String;
+Landroid/provider/Settings$System;->HEARING_AID:Ljava/lang/String;
+Landroid/provider/Settings$System;->MASTER_MONO:Ljava/lang/String;
Landroid/provider/Settings$System;->putStringForUser(Landroid/content/ContentResolver;Ljava/lang/String;Ljava/lang/String;I)Z
Landroid/provider/Settings$System;->sNameValueCache:Landroid/provider/Settings$NameValueCache;
Landroid/provider/Telephony$Sms;->addMessageToUri(ILandroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;ZZJ)Landroid/net/Uri;
@@ -1465,6 +1548,13 @@ Landroid/telephony/SignalStrength;->getLteRsrp()I
Landroid/telephony/SignalStrength;->getLteRsrq()I
Landroid/telephony/SignalStrength;->getLteRssnr()I
Landroid/telephony/SignalStrength;->getLteSignalStrength()I
+Landroid/telephony/SignalStrength;->mGsmBitErrorRate:I
+Landroid/telephony/SignalStrength;->mGsmSignalStrength:I
+Landroid/telephony/SignalStrength;->mLteCqi:I
+Landroid/telephony/SignalStrength;->mLteRsrp:I
+Landroid/telephony/SignalStrength;->mLteRsrq:I
+Landroid/telephony/SignalStrength;->mLteRssnr:I
+Landroid/telephony/SignalStrength;->mLteSignalStrength:I
Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_GOOD:I
Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_GREAT:I
Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_MODERATE:I
@@ -1516,6 +1606,7 @@ Landroid/telephony/TelephonyManager;-><init>(Landroid/content/Context;)V
Landroid/telephony/TelephonyManager;-><init>()V
Landroid/telephony/TelephonyManager;->isMultiSimEnabled()Z
Landroid/telephony/TelephonyManager;->isNetworkRoaming(I)Z
+Landroid/telephony/TelephonyManager;->isVolteAvailable()Z
Landroid/telephony/TelephonyManager;->setDataEnabled(IZ)V
Landroid/text/AndroidBidi;->bidi(I[C[B)I
Landroid/text/DynamicLayout;-><init>(Ljava/lang/CharSequence;Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout$Alignment;Landroid/text/TextDirectionHeuristic;FFZIIILandroid/text/TextUtils$TruncateAt;I)V
@@ -1581,6 +1672,7 @@ Landroid/util/DisplayMetrics;->noncompatWidthPixels:I
Landroid/util/EventLog$Event;-><init>([B)V
Landroid/util/Log;->wtf(ILjava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;ZZ)I
Landroid/util/Pools$SynchronizedPool;->acquire()Ljava/lang/Object;
+Landroid/util/Rational;->readObject(Ljava/io/ObjectInputStream;)V
Landroid/util/Singleton;->mInstance:Ljava/lang/Object;
Landroid/view/accessibility/AccessibilityManager;->getInstance(Landroid/content/Context;)Landroid/view/accessibility/AccessibilityManager;
Landroid/view/accessibility/AccessibilityManager;->isHighTextContrastEnabled()Z
@@ -1601,6 +1693,7 @@ Landroid/view/Choreographer;->postCallback(ILjava/lang/Runnable;Ljava/lang/Objec
Landroid/view/Choreographer;->removeCallbacks(ILjava/lang/Runnable;Ljava/lang/Object;)V
Landroid/view/Choreographer;->scheduleVsyncLocked()V
Landroid/view/Choreographer;->USE_VSYNC:Z
+Landroid/view/ContextThemeWrapper;->getThemeResId()I
Landroid/view/ContextThemeWrapper;->mResources:Landroid/content/res/Resources;
Landroid/view/ContextThemeWrapper;->mTheme:Landroid/content/res/Resources$Theme;
Landroid/view/ContextThemeWrapper;->mThemeResource:I
@@ -1626,6 +1719,7 @@ Landroid/view/InputDevice;->isExternal()Z
Landroid/view/InputEventReceiver;->dispatchBatchedInputEventPending()V
Landroid/view/InputEventReceiver;->dispatchInputEvent(ILandroid/view/InputEvent;I)V
Landroid/view/InputEventSender;->dispatchInputEventFinished(IZ)V
+Landroid/view/inputmethod/InputMethodInfo;->mSubtypes:Landroid/view/inputmethod/InputMethodSubtypeArray;
Landroid/view/inputmethod/InputMethodManager;->finishInputLocked()V
Landroid/view/inputmethod/InputMethodManager;->focusIn(Landroid/view/View;)V
Landroid/view/inputmethod/InputMethodManager;->getInputMethodWindowVisibleHeight()I
@@ -1639,12 +1733,15 @@ Landroid/view/inputmethod/InputMethodManager;->notifyUserAction()V
Landroid/view/inputmethod/InputMethodManager;->showSoftInputUnchecked(ILandroid/os/ResultReceiver;)V
Landroid/view/inputmethod/InputMethodManager;->sInstance:Landroid/view/inputmethod/InputMethodManager;
Landroid/view/inputmethod/InputMethodManager;->windowDismissed(Landroid/os/IBinder;)V
+Landroid/view/inputmethod/InputMethodSubtypeArray;-><init>(Ljava/util/List;)V
Landroid/view/InputQueue;->finishInputEvent(JZ)V
Landroid/view/IWindowManager;->getAnimationScale(I)F
Landroid/view/IWindowManager;->hasNavigationBar()Z
Landroid/view/IWindowManager;->setAnimationScale(IF)V
Landroid/view/IWindowManager;->setStrictModeVisualIndicatorPreference(Ljava/lang/String;)V
Landroid/view/IWindowManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/IWindowManager;
+Landroid/view/IWindowManager$Stub$Proxy;->getBaseDisplayDensity(I)I
+Landroid/view/IWindowManager$Stub$Proxy;->getInitialDisplayDensity(I)I
Landroid/view/IWindowManager$Stub$Proxy;->hasNavigationBar()Z
Landroid/view/IWindowManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/view/IWindowSession$Stub$Proxy;->relayout(Landroid/view/IWindow;ILandroid/view/WindowManager$LayoutParams;IIIILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/view/DisplayCutout$ParcelableWrapper;Landroid/util/MergedConfiguration;Landroid/view/Surface;)I
@@ -1801,6 +1898,7 @@ Landroid/view/View;->resetPaddingToInitialValues()V
Landroid/view/ViewRootImpl;->detachFunctor(J)V
Landroid/view/ViewRootImpl;->invokeFunctor(JZ)V
Landroid/view/ViewRootImpl;->mStopped:Z
+Landroid/view/ViewRootImpl;->mView:Landroid/view/View;
Landroid/view/View$ScrollabilityCache;->scrollBar:Landroid/widget/ScrollBarDrawable;
Landroid/view/View;->setAlphaNoInvalidation(F)Z
Landroid/view/View;->setAnimationMatrix(Landroid/graphics/Matrix;)V
@@ -1829,6 +1927,7 @@ Landroid/view/WindowManagerGlobal;->getInstance()Landroid/view/WindowManagerGlob
Landroid/view/WindowManagerGlobal;->getRootView(Ljava/lang/String;)Landroid/view/View;
Landroid/view/WindowManagerGlobal;->getViewRootNames()[Ljava/lang/String;
Landroid/view/WindowManagerGlobal;->getWindowManagerService()Landroid/view/IWindowManager;
+Landroid/view/WindowManagerGlobal;->initialize()V
Landroid/view/WindowManagerGlobal;->mLock:Ljava/lang/Object;
Landroid/view/WindowManagerGlobal;->mParams:Ljava/util/ArrayList;
Landroid/view/WindowManagerGlobal;->mRoots:Ljava/util/ArrayList;
@@ -2017,6 +2116,8 @@ Landroid/widget/MediaController;->mWindowManager:Landroid/view/WindowManager;
Landroid/widget/NumberPicker;->mInputText:Landroid/widget/EditText;
Landroid/widget/NumberPicker;->mSelectionDivider:Landroid/graphics/drawable/Drawable;
Landroid/widget/NumberPicker;->mSelectorWheelPaint:Landroid/graphics/Paint;
+Landroid/widget/OverScroller;->mScrollerY:Landroid/widget/OverScroller$SplineOverScroller;
+Landroid/widget/OverScroller$SplineOverScroller;->mCurrVelocity:F
Landroid/widget/PopupMenu;->mPopup:Lcom/android/internal/view/menu/MenuPopupHelper;
Landroid/widget/PopupWindow;->computeAnimationResource()I
Landroid/widget/PopupWindow;->createPopupLayoutParams(Landroid/os/IBinder;)Landroid/view/WindowManager$LayoutParams;
@@ -2033,6 +2134,7 @@ Landroid/widget/PopupWindow;->mLastHeight:I
Landroid/widget/PopupWindow;->mLastWidth:I
Landroid/widget/PopupWindow;->mOnScrollChangedListener:Landroid/view/ViewTreeObserver$OnScrollChangedListener;
Landroid/widget/PopupWindow;->mOverlapAnchor:Z
+Landroid/widget/PopupWindow;->mTouchInterceptor:Landroid/view/View$OnTouchListener;
Landroid/widget/PopupWindow;->mWidthMode:I
Landroid/widget/PopupWindow;->mWindowLayoutType:I
Landroid/widget/PopupWindow;->preparePopup(Landroid/view/WindowManager$LayoutParams;)V
@@ -2055,10 +2157,14 @@ Landroid/widget/RelativeLayout;->mGravity:I
Landroid/widget/RemoteViews$Action;->mergeBehavior()I
Landroid/widget/RemoteViews$Action;->viewId:I
Landroid/widget/RemoteViews$BitmapCache;->mBitmaps:Ljava/util/ArrayList;
+Landroid/widget/RemoteViews$BitmapReflectionAction;->bitmap:Landroid/graphics/Bitmap;
+Landroid/widget/RemoteViews$BitmapReflectionAction;->methodName:Ljava/lang/String;
+Landroid/widget/RemoteViews;->estimateMemoryUsage()I
Landroid/widget/RemoteViews;->mActions:Ljava/util/ArrayList;
Landroid/widget/RemoteViews;->mApplication:Landroid/content/pm/ApplicationInfo;
Landroid/widget/RemoteViews;->mBitmapCache:Landroid/widget/RemoteViews$BitmapCache;
Landroid/widget/RemoteViews;->mergeRemoteViews(Landroid/widget/RemoteViews;)V
+Landroid/widget/RemoteViews;->mPortrait:Landroid/widget/RemoteViews;
Landroid/widget/RemoteViews$ReflectionAction;->methodName:Ljava/lang/String;
Landroid/widget/ScrollBarDrawable;->mVerticalThumb:Landroid/graphics/drawable/Drawable;
Landroid/widget/ScrollBarDrawable;->setHorizontalThumbDrawable(Landroid/graphics/drawable/Drawable;)V
@@ -2091,6 +2197,7 @@ Landroid/widget/TextView;->mMarquee:Landroid/widget/TextView$Marquee;
Landroid/widget/TextView;->mMaximum:I
Landroid/widget/TextView;->mMaxMode:I
Landroid/widget/TextView;->mSingleLine:Z
+Landroid/widget/TextView;->mTextPaint:Landroid/text/TextPaint;
Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;Landroid/widget/TextView$BufferType;ZI)V
Landroid/widget/Toast;->getService()Landroid/app/INotificationManager;
Landroid/widget/Toast;->sService:Landroid/app/INotificationManager;
@@ -2100,6 +2207,7 @@ Landroid/widget/VideoView;->mSHCallback:Landroid/view/SurfaceHolder$Callback;
Landroid/widget/VideoView;->mUri:Landroid/net/Uri;
Landroid/widget/VideoView;->mVideoHeight:I
Landroid/widget/VideoView;->mVideoWidth:I
+Lcom/android/internal/app/IAppOpsService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IAppOpsService;
Lcom/android/internal/app/IAppOpsService$Stub$Proxy;->checkOperation(IILjava/lang/String;)I
Lcom/android/internal/app/IAppOpsService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/app/IBatteryStats;->getStatistics()[B
@@ -2190,6 +2298,13 @@ Lcom/android/internal/R$id;->title:I
Lcom/android/internal/R$integer;->config_screenBrightnessDim:I
Lcom/android/internal/R$integer;->config_toastDefaultGravity:I
Lcom/android/internal/R$layout;->screen_title:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_accountPreferences:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_accountType:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_customTokens:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator:[I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_icon:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_label:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_smallIcon:I
Lcom/android/internal/R$styleable;->AndroidManifestApplication_enabled:I
Lcom/android/internal/R$styleable;->AndroidManifestApplication_hardwareAccelerated:I
Lcom/android/internal/R$styleable;->AndroidManifestApplication:[I
@@ -2220,6 +2335,14 @@ Lcom/android/internal/R$styleable;->ImageView:[I
Lcom/android/internal/R$styleable;->ImageView_src:I
Lcom/android/internal/R$styleable;->ScrollView_fillViewport:I
Lcom/android/internal/R$styleable;->ScrollView:[I
+Lcom/android/internal/R$styleable;->SyncAdapter_accountType:I
+Lcom/android/internal/R$styleable;->SyncAdapter_allowParallelSyncs:I
+Lcom/android/internal/R$styleable;->SyncAdapter_contentAuthority:I
+Lcom/android/internal/R$styleable;->SyncAdapter:[I
+Lcom/android/internal/R$styleable;->SyncAdapter_isAlwaysSyncable:I
+Lcom/android/internal/R$styleable;->SyncAdapter_settingsActivity:I
+Lcom/android/internal/R$styleable;->SyncAdapter_supportsUploading:I
+Lcom/android/internal/R$styleable;->SyncAdapter_userVisible:I
Lcom/android/internal/R$styleable;->TabWidget:[I
Lcom/android/internal/R$styleable;->TextView_drawableBottom:I
Lcom/android/internal/R$styleable;->TextView_drawableLeft:I
@@ -2235,7 +2358,11 @@ Lcom/android/internal/R$styleable;->View_id:I
Lcom/android/internal/R$styleable;->ViewStub:[I
Lcom/android/internal/R$styleable;->ViewStub_inflatedId:I
Lcom/android/internal/R$styleable;->ViewStub_layout:I
+Lcom/android/internal/R$styleable;->Window:[I
Lcom/android/internal/R$styleable;->Window_windowActionBarFullscreenDecorLayout:I
+Lcom/android/internal/R$styleable;->Window_windowIsFloating:I
+Lcom/android/internal/R$styleable;->Window_windowIsTranslucent:I
+Lcom/android/internal/R$styleable;->Window_windowShowWallpaper:I
Lcom/android/internal/R$style;->Theme:I
Lcom/android/internal/R$xml;->power_profile:I
Lcom/android/internal/telephony/IPhoneSubInfo$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IPhoneSubInfo;
@@ -2268,6 +2395,8 @@ Lcom/android/okhttp/OkHttpClient;->connectionPool:Lcom/android/okhttp/Connection
Lcom/android/okhttp/OkHttpClient;->DEFAULT_PROTOCOLS:Ljava/util/List;
Lcom/android/okhttp/OkHttpClient;->dns:Lcom/android/okhttp/Dns;
Lcom/android/okhttp/OkHttpClient;->setProtocols(Ljava/util/List;)Lcom/android/okhttp/OkHttpClient;
+Lcom/android/okhttp/okio/ByteString;->readObject(Ljava/io/ObjectInputStream;)V
+Lcom/android/okhttp/okio/ByteString;->writeObject(Ljava/io/ObjectOutputStream;)V
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getAlpnSelectedProtocol()[B
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getNpnSelectedProtocol()[B
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setAlpnProtocols([B)V
@@ -2283,6 +2412,7 @@ Ldalvik/system/CloseGuard;->close()V
Ldalvik/system/CloseGuard;->get()Ldalvik/system/CloseGuard;
Ldalvik/system/CloseGuard;->open(Ljava/lang/String;)V
Ldalvik/system/CloseGuard;->warnIfOpen()V
+Ldalvik/system/DexFile;->getClassNameList(Ljava/lang/Object;)[Ljava/lang/String;
Ldalvik/system/DexFile;->loadClassBinaryName(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/util/List;)Ljava/lang/Class;
Ldalvik/system/DexFile;->mCookie:Ljava/lang/Object;
Ldalvik/system/DexFile;->mFileName:Ljava/lang/String;
@@ -2294,10 +2424,12 @@ Ldalvik/system/DexPathList$Element;-><init>(Ldalvik/system/DexFile;Ljava/io/File
Ldalvik/system/DexPathList$Element;-><init>(Ljava/io/File;ZLjava/io/File;Ldalvik/system/DexFile;)V
Ldalvik/system/DexPathList;-><init>(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;Ljava/io/File;)V
Ldalvik/system/DexPathList;->makeDexElements(Ljava/util/List;Ljava/io/File;Ljava/util/List;Ljava/lang/ClassLoader;)[Ldalvik/system/DexPathList$Element;
+Ldalvik/system/DexPathList;->makeInMemoryDexElements([Ljava/nio/ByteBuffer;Ljava/util/List;)[Ldalvik/system/DexPathList$Element;
Ldalvik/system/DexPathList;->makePathElements(Ljava/util/List;)[Ldalvik/system/DexPathList$NativeLibraryElement;
Ldalvik/system/DexPathList;->makePathElements(Ljava/util/List;Ljava/io/File;Ljava/util/List;)[Ldalvik/system/DexPathList$Element;
Ldalvik/system/DexPathList;->nativeLibraryDirectories:Ljava/util/List;
Ldalvik/system/DexPathList$NativeLibraryElement;-><init>(Ljava/io/File;)V
+Ldalvik/system/DexPathList$NativeLibraryElement;->path:Ljava/io/File;
Ldalvik/system/DexPathList;->nativeLibraryPathElements:[Ldalvik/system/DexPathList$NativeLibraryElement;
Ldalvik/system/DexPathList;->splitPaths(Ljava/lang/String;Z)Ljava/util/List;
Ldalvik/system/DexPathList;->systemNativeLibraryDirectories:Ljava/util/List;
@@ -2313,20 +2445,27 @@ Ldalvik/system/VMRuntime;->registerNativeFree(I)V
Ldalvik/system/VMRuntime;->runFinalization(J)V
Ldalvik/system/VMRuntime;->setMinimumHeapSize(J)J
Ldalvik/system/VMRuntime;->setTargetHeapUtilization(F)F
+Ldalvik/system/VMRuntime;->setTargetSdkVersion(I)V
Ldalvik/system/VMRuntime;->trackExternalAllocation(J)Z
Ldalvik/system/VMRuntime;->trackExternalFree(J)V
Ldalvik/system/VMRuntime;->vmInstructionSet()Ljava/lang/String;
Ldalvik/system/VMRuntime;->vmLibrary()Ljava/lang/String;
Ldalvik/system/VMStack;->getCallingClassLoader()Ljava/lang/ClassLoader;
Ldalvik/system/VMStack;->getStackClass2()Ljava/lang/Class;
+Ljava/awt/font/NumericShaper;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/beans/PropertyChangeSupport;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/beans/PropertyChangeSupport;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/io/FileDescriptor;->descriptor:I
Ljava/io/FileDescriptor;->getInt$()I
Ljava/io/FileDescriptor;->setInt$(I)V
Ljava/io/FileInputStream;->fd:Ljava/io/FileDescriptor;
Ljava/io/FileOutputStream;->fd:Ljava/io/FileDescriptor;
+Ljava/io/File;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/io/File;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/io/ObjectStreamClass;->getConstructorId(Ljava/lang/Class;)J
Ljava/io/ObjectStreamClass;->newInstance(Ljava/lang/Class;J)Ljava/lang/Object;
Ljava/io/ObjectStreamClass;->newInstance()Ljava/lang/Object;
+Ljava/io/UncheckedIOException;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/lang/AbstractStringBuilder;->value:[C
Ljava/lang/Boolean;->value:Z
Ljava/lang/Byte;->value:B
@@ -2347,8 +2486,11 @@ Ljava/lang/Daemons;->requestHeapTrim()V
Ljava/lang/Daemons;->start()V
Ljava/lang/Daemons;->stop()V
Ljava/lang/Double;->value:D
+Ljava/lang/Enum;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/lang/Float;->value:F
Ljava/lang/Integer;->value:I
+Ljava/lang/invoke/MethodType;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/lang/invoke/MethodType;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/lang/Long;->value:J
Ljava/lang/ref/FinalizerReference;->add(Ljava/lang/Object;)V
Ljava/lang/ref/FinalizerReference;->head:Ljava/lang/ref/FinalizerReference;
@@ -2364,6 +2506,10 @@ Ljava/lang/Runtime;->loadLibrary(Ljava/lang/String;Ljava/lang/ClassLoader;)V
Ljava/lang/Runtime;->load(Ljava/lang/String;Ljava/lang/ClassLoader;)V
Ljava/lang/Runtime;->nativeLoad(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/String;
Ljava/lang/Short;->value:S
+Ljava/lang/StringBuffer;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/lang/StringBuffer;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/lang/StringBuilder;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/lang/StringBuilder;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/lang/String;-><init>(II[C)V
Ljava/lang/Thread;->daemon:Z
Ljava/lang/Thread;->dispatchUncaughtException(Ljava/lang/Throwable;)V
@@ -2385,12 +2531,20 @@ Ljava/lang/Thread;->priority:I
Ljava/lang/Throwable;->backtrace:Ljava/lang/Object;
Ljava/lang/Throwable;->cause:Ljava/lang/Throwable;
Ljava/lang/Throwable;->detailMessage:Ljava/lang/String;
+Ljava/lang/Throwable;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/lang/Throwable;->stackTrace:[Ljava/lang/StackTraceElement;
Ljava/lang/Throwable;->suppressedExceptions:Ljava/util/List;
+Ljava/lang/Throwable;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/lang/Void;-><init>()V
+Ljava/math/BigDecimal;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/math/BigDecimal;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/math/BigInteger;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/math/BigInteger;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/math/MathContext;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/net/Authenticator;->theAuthenticator:Ljava/net/Authenticator;
Ljava/net/DatagramSocket;->impl:Ljava/net/DatagramSocketImpl;
Ljava/net/HttpCookie;->httpOnly:Z
+Ljava/net/HttpCookie;->whenCreated:J
Ljava/net/Inet4Address;-><init>()V
Ljava/net/Inet6Address;->holder6:Ljava/net/Inet6Address$Inet6AddressHolder;
Ljava/net/Inet6Address$Inet6AddressHolder;->ipaddress:[B
@@ -2398,6 +2552,8 @@ Ljava/net/Inet6Address$Inet6AddressHolder;->scope_id:I
Ljava/net/Inet6Address$Inet6AddressHolder;->scope_id_set:Z
Ljava/net/Inet6Address$Inet6AddressHolder;->scope_ifname:Ljava/net/NetworkInterface;
Ljava/net/Inet6Address;-><init>()V
+Ljava/net/Inet6Address;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/net/Inet6Address;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/net/InetAddress;->clearDnsCache()V
Ljava/net/InetAddress;->holder:Ljava/net/InetAddress$InetAddressHolder;
Ljava/net/InetAddress$InetAddressHolder;->address:I
@@ -2406,10 +2562,18 @@ Ljava/net/InetAddress$InetAddressHolder;->hostName:Ljava/lang/String;
Ljava/net/InetAddress$InetAddressHolder;->originalHostName:Ljava/lang/String;
Ljava/net/InetAddress;->isNumeric(Ljava/lang/String;)Z
Ljava/net/InetAddress;->parseNumericAddress(Ljava/lang/String;)Ljava/net/InetAddress;
+Ljava/net/InetAddress;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/net/InetAddress;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/net/InetSocketAddress;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/net/InetSocketAddress;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/net/Socket;->getFileDescriptor$()Ljava/io/FileDescriptor;
Ljava/net/Socket;->impl:Ljava/net/SocketImpl;
Ljava/net/URI;->host:Ljava/lang/String;
+Ljava/net/URI;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/net/URI;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/net/URL;->handlers:Ljava/util/Hashtable;
+Ljava/net/URL;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/net/URL;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/nio/Buffer;->address:J
Ljava/nio/Buffer;->capacity:I
Ljava/nio/Buffer;->_elementSizeShift:I
@@ -2420,29 +2584,162 @@ Ljava/nio/ByteBuffer;->isReadOnly:Z
Ljava/nio/ByteBuffer;->offset:I
Ljava/nio/charset/CharsetEncoder;->canEncode(Ljava/nio/CharBuffer;)Z
Ljava/nio/DirectByteBuffer;-><init>(JI)V
+Ljava/nio/file/DirectoryIteratorException;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/nio/NIOAccess;->getBaseArray(Ljava/nio/Buffer;)Ljava/lang/Object;
Ljava/nio/NIOAccess;->getBaseArrayOffset(Ljava/nio/Buffer;)I
Ljava/nio/NIOAccess;->getBasePointer(Ljava/nio/Buffer;)J
+Ljava/security/cert/CertificateRevokedException;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/security/cert/CertificateRevokedException;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/security/cert/CertPathValidatorException;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/security/CodeSigner;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/security/GuardedObject;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/security/Provider;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/security/SignedObject;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/security/spec/ECParameterSpec;->getCurveName()Ljava/lang/String;
Ljava/security/spec/ECParameterSpec;->setCurveName(Ljava/lang/String;)V
+Ljava/security/Timestamp;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/text/ChoiceFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/text/DateFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/text/DateFormatSymbols;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/text/DecimalFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/text/DecimalFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/text/DecimalFormatSymbols;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/text/DecimalFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/text/MessageFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/text/NumberFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/text/NumberFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/text/SimpleDateFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/AbstractChronology;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/HijrahChronology;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/HijrahDate;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/IsoChronology;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/JapaneseChronology;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/JapaneseDate;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/JapaneseEra;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/MinguoChronology;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/MinguoDate;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/ThaiBuddhistChronology;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/ThaiBuddhistDate;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/Duration;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/Instant;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/LocalDate;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/LocalDateTime;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/LocalTime;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/MonthDay;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/OffsetDateTime;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/OffsetTime;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/Period;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/temporal/ValueRange;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/temporal/WeekFields;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/YearMonth;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/Year;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/ZonedDateTime;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/ZoneId;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/ZoneOffset;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/zone/ZoneOffsetTransition;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/zone/ZoneOffsetTransitionRule;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/zone/ZoneRules;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/ArrayDeque;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/ArrayDeque;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/ArrayList;->elementData:[Ljava/lang/Object;
+Ljava/util/ArrayList;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/util/ArrayList;->size:I
Ljava/util/ArrayList$SubList;->parent:Ljava/util/AbstractList;
Ljava/util/ArrayList$SubList;->parentOffset:I
Ljava/util/ArrayList$SubList;->size:I
+Ljava/util/ArrayList;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/Arrays$ArrayList;->a:[Ljava/lang/Object;
+Ljava/util/BitSet;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/BitSet;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/Calendar;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/Calendar;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/Calendar;->zone:Ljava/util/TimeZone;
Ljava/util/Collections$EmptyList;-><init>()V
+Ljava/util/Collections$SetFromMap;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/util/Collections$SynchronizedCollection;->c:Ljava/util/Collection;
+Ljava/util/Collections$SynchronizedCollection;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/Collections$SynchronizedMap;->m:Ljava/util/Map;
+Ljava/util/Collections$SynchronizedMap;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/Collections$UnmodifiableCollection;->c:Ljava/util/Collection;
Ljava/util/Collections$UnmodifiableMap;->m:Ljava/util/Map;
+Ljava/util/concurrent/atomic/AtomicReferenceArray;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/atomic/DoubleAccumulator;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/atomic/DoubleAdder;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/atomic/LongAccumulator;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/atomic/LongAdder;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/ConcurrentHashMap;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/ConcurrentHashMap;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/concurrent/ConcurrentLinkedDeque;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/ConcurrentLinkedDeque;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/concurrent/ConcurrentLinkedQueue;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/ConcurrentLinkedQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/concurrent/ConcurrentSkipListMap;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/ConcurrentSkipListMap;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/concurrent/CopyOnWriteArrayList;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/CopyOnWriteArrayList;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/concurrent/ForkJoinTask;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/ForkJoinTask;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/concurrent/FutureTask;->callable:Ljava/util/concurrent/Callable;
+Ljava/util/concurrent/LinkedBlockingDeque;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/LinkedBlockingDeque;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/concurrent/LinkedBlockingQueue;->capacity:I
+Ljava/util/concurrent/LinkedBlockingQueue;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/LinkedBlockingQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/concurrent/LinkedTransferQueue;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/LinkedTransferQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/concurrent/locks/ReentrantLock$Sync;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/locks/ReentrantReadWriteLock$Sync;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/locks/StampedLock;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/PriorityBlockingQueue;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/PriorityBlockingQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/concurrent/SynchronousQueue;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/SynchronousQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/concurrent/ThreadLocalRandom;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/Date;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/Date;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/EnumMap;->keyType:Ljava/lang/Class;
+Ljava/util/EnumMap;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/EnumMap;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/EnumSet;->elementType:Ljava/lang/Class;
+Ljava/util/EnumSet;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/GregorianCalendar;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/util/HashMap$HashIterator;->hasNext()Z
+Ljava/util/HashMap;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/HashMap;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/HashSet;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/HashSet;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/Hashtable;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/Hashtable;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/IdentityHashMap;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/IdentityHashMap;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/InvalidPropertiesFormatException;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/InvalidPropertiesFormatException;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/LinkedHashMap;->eldest()Ljava/util/Map$Entry;
+Ljava/util/LinkedList;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/LinkedList;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/Locale;->createConstant(Ljava/lang/String;Ljava/lang/String;)Ljava/util/Locale;
+Ljava/util/Locale;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/Locale;->readResolve()Ljava/lang/Object;
+Ljava/util/Locale;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/logging/LogRecord;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/logging/LogRecord;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/prefs/NodeChangeEvent;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/prefs/NodeChangeEvent;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/prefs/PreferenceChangeEvent;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/prefs/PreferenceChangeEvent;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/PriorityQueue;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/PriorityQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/Random;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/Random;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/regex/Matcher;->appendPos:I
+Ljava/util/regex/Pattern;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/SimpleTimeZone;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/SimpleTimeZone;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/TreeMap;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/TreeMap;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/TreeSet;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/TreeSet;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/Vector;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/zip/Deflater;->buf:[B
Ljava/util/zip/Deflater;->finished:Z
Ljava/util/zip/Deflater;->finish:Z
@@ -2458,11 +2755,23 @@ Ljava/util/zip/Inflater;->needDict:Z
Ljava/util/zip/Inflater;->off:I
Ljava/util/zip/ZipEntry;-><init>(Ljava/lang/String;Ljava/lang/String;JJJII[BJ)V
Ljava/util/zip/ZipFile;->jzfile:J
+Ljavax/crypto/SealedObject;->readObject(Ljava/io/ObjectInputStream;)V
Ljavax/net/ssl/SSLServerSocketFactory;->defaultServerSocketFactory:Ljavax/net/ssl/SSLServerSocketFactory;
Ljavax/net/ssl/SSLSocketFactory;->defaultSocketFactory:Ljavax/net/ssl/SSLSocketFactory;
+Ljavax/security/auth/Subject;->readObject(Ljava/io/ObjectInputStream;)V
+Ljavax/security/auth/Subject$SecureSet;->readObject(Ljava/io/ObjectInputStream;)V
+Ljavax/security/auth/Subject$SecureSet;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljavax/security/auth/Subject;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljavax/security/auth/x500/X500Principal;->readObject(Ljava/io/ObjectInputStream;)V
+Ljavax/security/auth/x500/X500Principal;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljavax/xml/datatype/DatatypeConfigurationException;->readObject(Ljava/io/ObjectInputStream;)V
+Ljavax/xml/namespace/QName;->readObject(Ljava/io/ObjectInputStream;)V
Llibcore/util/ZoneInfo;->mTransitions:[J
+Llibcore/util/ZoneInfo;->readObject(Ljava/io/ObjectInputStream;)V
Lorg/apache/http/conn/ssl/SSLSocketFactory;-><init>(Ljavax/net/ssl/SSLSocketFactory;)V
Lorg/apache/http/conn/ssl/SSLSocketFactory;-><init>()V
Lorg/json/JSONArray;->values:Ljava/util/List;
Lorg/json/JSONObject;->writeTo(Lorg/json/JSONStringer;)V
Lsun/misc/Unsafe;->theUnsafe:Lsun/misc/Unsafe;
+Lsun/security/util/ObjectIdentifier;->readObject(Ljava/io/ObjectInputStream;)V
+Lsun/security/util/ObjectIdentifier;->writeObject(Ljava/io/ObjectOutputStream;)V
diff --git a/core/java/Android.bp b/core/java/Android.bp
index f7c5c57a07e4..fb27f74211fb 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -7,33 +7,3 @@ filegroup {
name: "IDropBoxManagerService.aidl",
srcs: ["com/android/internal/os/IDropBoxManagerService.aidl"],
}
-
-// only used by key_store_service
-cc_library_shared {
- name: "libkeystore_aidl",
- srcs: ["android/security/IKeystoreService.aidl",
- "android/security/IConfirmationPromptCallback.aidl"],
- aidl: {
- export_aidl_headers: true,
- include_dirs: [
- "frameworks/base/core/java/",
- "system/security/keystore/",
- ],
- },
- shared_libs: [
- "libbinder",
- "libcutils",
- "libhardware",
- "libhidlbase",
- "libhidltransport",
- "libhwbinder",
- "liblog",
- "libkeystore_parcelables",
- "libselinux",
- "libutils",
- ],
- export_shared_lib_headers: [
- "libbinder",
- "libkeystore_parcelables",
- ],
-}
diff --git a/core/java/android/annotation/OWNERS b/core/java/android/annotation/OWNERS
new file mode 100644
index 000000000000..d6bb71b50e34
--- /dev/null
+++ b/core/java/android/annotation/OWNERS
@@ -0,0 +1 @@
+tnorbye@google.com
diff --git a/core/java/android/annotation/RequiresFeature.java b/core/java/android/annotation/RequiresFeature.java
new file mode 100644
index 000000000000..fc93f03d76cf
--- /dev/null
+++ b/core/java/android/annotation/RequiresFeature.java
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+package android.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.content.pm.PackageManager;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes that the annotated element requires one or more device features. This
+ * is used to auto-generate documentation.
+ *
+ * @see PackageManager#hasSystemFeature(String)
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({TYPE,FIELD,METHOD,CONSTRUCTOR})
+public @interface RequiresFeature {
+ /**
+ * The name of the device feature that is required.
+ *
+ * @see PackageManager#hasSystemFeature(String)
+ */
+ String value();
+}
diff --git a/core/java/android/annotation/SystemService.java b/core/java/android/annotation/SystemService.java
index ba5002a4f1b5..0c5d15e178a3 100644
--- a/core/java/android/annotation/SystemService.java
+++ b/core/java/android/annotation/SystemService.java
@@ -26,12 +26,19 @@ import java.lang.annotation.Target;
/**
* Description of a system service available through
- * {@link Context#getSystemService(Class)}.
+ * {@link Context#getSystemService(Class)}. This is used to auto-generate
+ * documentation explaining how to obtain a reference to the service.
*
* @hide
*/
@Retention(SOURCE)
@Target(TYPE)
public @interface SystemService {
+ /**
+ * The string name of the system service that can be passed to
+ * {@link Context#getSystemService(String)}.
+ *
+ * @see Context#getSystemServiceName(Class)
+ */
String value();
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 0bc510a13ba6..8a9efe876321 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -17,6 +17,7 @@
package android.app;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
+
import static java.lang.Character.MIN_VALUE;
import android.annotation.CallSuper;
@@ -135,6 +136,7 @@ import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -1733,7 +1735,7 @@ public class Activity extends ContextThemeWrapper
*
* <p>This callback and {@link #onUserInteraction} are intended to help
* activities manage status bar notifications intelligently; specifically,
- * for helping activities determine the proper time to cancel a notfication.
+ * for helping activities determine the proper time to cancel a notification.
*
* @see #onUserInteraction()
*/
@@ -1741,32 +1743,16 @@ public class Activity extends ContextThemeWrapper
}
/**
- * Generate a new thumbnail for this activity. This method is called before
- * pausing the activity, and should draw into <var>outBitmap</var> the
- * imagery for the desired thumbnail in the dimensions of that bitmap. It
- * can use the given <var>canvas</var>, which is configured to draw into the
- * bitmap, for rendering if desired.
- *
- * <p>The default implementation returns fails and does not draw a thumbnail;
- * this will result in the platform creating its own thumbnail if needed.
- *
- * @param outBitmap The bitmap to contain the thumbnail.
- * @param canvas Can be used to render into the bitmap.
- *
- * @return Return true if you have drawn into the bitmap; otherwise after
- * you return it will be filled with a default thumbnail.
- *
- * @see #onCreateDescription
- * @see #onSaveInstanceState
- * @see #onPause
+ * @deprecated Method doesn't do anything and will be removed in the future.
*/
+ @Deprecated
public boolean onCreateThumbnail(Bitmap outBitmap, Canvas canvas) {
return false;
}
/**
* Generate a new description for this activity. This method is called
- * before pausing the activity and can, if desired, return some textual
+ * before stopping the activity and can, if desired, return some textual
* description of its current state to be displayed to the user.
*
* <p>The default implementation returns null, which will cause you to
@@ -1777,9 +1763,8 @@ public class Activity extends ContextThemeWrapper
* @return A description of what the user is doing. It should be short and
* sweet (only a few words).
*
- * @see #onCreateThumbnail
* @see #onSaveInstanceState
- * @see #onPause
+ * @see #onStop
*/
@Nullable
public CharSequence onCreateDescription() {
@@ -1915,7 +1900,7 @@ public class Activity extends ContextThemeWrapper
if (isFinishing()) {
if (mAutoFillResetNeeded) {
- getAutofillManager().onActivityFinished();
+ getAutofillManager().onActivityFinishing();
} else if (mIntent != null
&& mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)) {
// Activity was launched when user tapped a link in the Autofill Save UI - since
@@ -7179,8 +7164,8 @@ public class Activity extends ContextThemeWrapper
String appName = getApplicationInfo().loadLabel(getPackageManager())
.toString();
- String warning = "Detected problems with API compatiblity\n"
- + "(please consult log for detail)";
+ String warning = "Detected problems with API compatibility\n"
+ + "(visit g.co/dev/appcompat for more info)";
if (isAppDebuggable) {
new AlertDialog.Builder(this)
.setTitle(appName)
@@ -7706,6 +7691,9 @@ public class Activity extends ContextThemeWrapper
}
}
}
+ if (android.view.autofill.Helper.sVerbose) {
+ Log.v(TAG, "autofillClientGetViewVisibility(): " + Arrays.toString(visible));
+ }
return visible;
}
@@ -7768,7 +7756,6 @@ public class Activity extends ContextThemeWrapper
* @param disable {@code true} to disable preview screenshots; {@code false} otherwise.
* @hide
*/
- @SystemApi
public void setDisablePreviewScreenshots(boolean disable) {
try {
ActivityManager.getService().setDisablePreviewScreenshots(mToken, disable);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index ae47a684f6ab..03faeeeb91a1 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -44,6 +44,7 @@ import android.graphics.GraphicBuffer;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
+import android.net.Uri;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Build;
@@ -2750,6 +2751,30 @@ public class ActivityManager {
}
/**
+ * Updates (grants or revokes) a persitable URI permission.
+ *
+ * @param uri URI to be granted or revoked.
+ * @param prefix if {@code false}, permission apply to this specific URI; if {@code true}, it
+ * applies to all URIs that are prefixed by this URI.
+ * @param packageName target package.
+ * @param grant if {@code true} a new permission will be granted, otherwise an existing
+ * permission will be revoked.
+ *
+ * @return whether or not the requested succeeded.
+ *
+ * @hide
+ */
+ public boolean updatePersistableUriPermission(Uri uri, boolean prefix, String packageName,
+ boolean grant) {
+ try {
+ return getService().updatePersistableUriPermission(uri, prefix, packageName, grant,
+ UserHandle.myUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Information you can retrieve about any processes that are in an error condition.
*/
public static class ProcessErrorStateInfo implements Parcelable {
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index b365d52313ca..0c98267cfd68 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -356,4 +356,9 @@ public abstract class ActivityManagerInternal {
* Whether an UID is active or idle.
*/
public abstract boolean isUidActive(int uid);
+
+ /**
+ * Returns a list that contains the memory stats for currently running processes.
+ */
+ public abstract List<ProcessMemoryState> getMemoryStateForProcesses();
}
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index fee58274a5fc..d5430f05d65b 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -1106,6 +1106,11 @@ public class ActivityOptions {
}
/** @hide */
+ public void setRemoteAnimationAdapter(RemoteAnimationAdapter remoteAnimationAdapter) {
+ mRemoteAnimationAdapter = remoteAnimationAdapter;
+ }
+
+ /** @hide */
public static ActivityOptions fromBundle(Bundle bOptions) {
return bOptions != null ? new ActivityOptions(bOptions) : null;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5a6331919d76..a69b0ee70f4d 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3904,62 +3904,6 @@ public final class ActivityThread extends ClientTransactionHandler {
}
}
- private int mThumbnailWidth = -1;
- private int mThumbnailHeight = -1;
- private Bitmap mAvailThumbnailBitmap = null;
- private Canvas mThumbnailCanvas = null;
-
- private Bitmap createThumbnailBitmap(ActivityClientRecord r) {
- Bitmap thumbnail = mAvailThumbnailBitmap;
- try {
- if (thumbnail == null) {
- int w = mThumbnailWidth;
- int h;
- if (w < 0) {
- Resources res = r.activity.getResources();
- int wId = com.android.internal.R.dimen.thumbnail_width;
- int hId = com.android.internal.R.dimen.thumbnail_height;
- mThumbnailWidth = w = res.getDimensionPixelSize(wId);
- mThumbnailHeight = h = res.getDimensionPixelSize(hId);
- } else {
- h = mThumbnailHeight;
- }
-
- // On platforms where we don't want thumbnails, set dims to (0,0)
- if ((w > 0) && (h > 0)) {
- thumbnail = Bitmap.createBitmap(r.activity.getResources().getDisplayMetrics(),
- w, h, THUMBNAIL_FORMAT);
- thumbnail.eraseColor(0);
- }
- }
-
- if (thumbnail != null) {
- Canvas cv = mThumbnailCanvas;
- if (cv == null) {
- mThumbnailCanvas = cv = new Canvas();
- }
-
- cv.setBitmap(thumbnail);
- if (!r.activity.onCreateThumbnail(thumbnail, cv)) {
- mAvailThumbnailBitmap = thumbnail;
- thumbnail = null;
- }
- cv.setBitmap(null);
- }
-
- } catch (Exception e) {
- if (!mInstrumentation.onException(r.activity, e)) {
- throw new RuntimeException(
- "Unable to create thumbnail of "
- + r.intent.getComponent().toShortString()
- + ": " + e.toString(), e);
- }
- thumbnail = null;
- }
-
- return thumbnail;
- }
-
@Override
public void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
int configChanges, boolean dontReport, PendingTransactionActions pendingActions) {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 4c9fb74c9c80..1026550b9b6b 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -543,7 +543,6 @@ public class AppOpsManager {
OP_CAMERA,
// Body sensors
OP_BODY_SENSORS,
- OP_REQUEST_DELETE_PACKAGES,
// APPOP PERMISSIONS
OP_ACCESS_NOTIFICATIONS,
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 02be00268a45..54fd0c45a811 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -68,6 +68,7 @@ import android.os.WorkSource;
import android.service.voice.IVoiceInteractionSession;
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationDefinition;
+import android.view.RemoteAnimationAdapter;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.IResultReceiver;
import com.android.internal.policy.IKeyguardDismissCallback;
@@ -423,6 +424,8 @@ interface IActivityManager {
void restart();
void performIdleMaintenance();
void takePersistableUriPermission(in Uri uri, int modeFlags, int userId);
+ boolean updatePersistableUriPermission(in Uri uri, boolean prefix, String packageName,
+ boolean grant, int userId);
void releasePersistableUriPermission(in Uri uri, int modeFlags, int userId);
ParceledListSlice getPersistedUriPermissions(in String packageName, boolean incoming);
void appNotRespondingViaProvider(in IBinder connection);
@@ -683,17 +686,24 @@ interface IActivityManager {
// If a transaction which will also be used on the native side is being inserted, add it
// alongside with other transactions of this kind at the top of this file.
- void setShowWhenLocked(in IBinder token, boolean showWhenLocked);
- void setTurnScreenOn(in IBinder token, boolean turnScreenOn);
+ void setShowWhenLocked(in IBinder token, boolean showWhenLocked);
+ void setTurnScreenOn(in IBinder token, boolean turnScreenOn);
- /**
- * Similar to {@link #startUserInBackground(int userId), but with a listener to report
- * user unlock progress.
- */
- boolean startUserInBackgroundWithListener(int userid, IProgressListener unlockProgressListener);
+ /**
+ * Similar to {@link #startUserInBackground(int userId), but with a listener to report
+ * user unlock progress.
+ */
+ boolean startUserInBackgroundWithListener(int userid, IProgressListener unlockProgressListener);
- /**
- * Registers remote animations for a specific activity.
- */
- void registerRemoteAnimations(in IBinder token, in RemoteAnimationDefinition definition);
+ /**
+ * Registers remote animations for a specific activity.
+ */
+ void registerRemoteAnimations(in IBinder token, in RemoteAnimationDefinition definition);
+
+ /**
+ * Registers a remote animation to be run for all activity starts from a certain package during
+ * a short predefined amount of time.
+ */
+ void registerRemoteAnimationForNextActivityStart(in String packageName,
+ in RemoteAnimationAdapter adapter);
}
diff --git a/core/java/android/app/IAlarmManager.aidl b/core/java/android/app/IAlarmManager.aidl
index 7b05b4918103..ded4c4954956 100644
--- a/core/java/android/app/IAlarmManager.aidl
+++ b/core/java/android/app/IAlarmManager.aidl
@@ -37,4 +37,5 @@ interface IAlarmManager {
void remove(in PendingIntent operation, in IAlarmListener listener);
long getNextWakeFromIdleTime();
AlarmManager.AlarmClockInfo getNextAlarmClock(int userId);
+ long currentNetworkTimeMillis();
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index c80565869f56..e80610b0fa83 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -8862,6 +8862,7 @@ public class Notification implements Parcelable
private static final String EXTRA_CONTENT_INTENT = "content_intent";
private static final String EXTRA_DELETE_INTENT = "delete_intent";
private static final String EXTRA_CHANNEL_ID = "channel_id";
+ private static final String EXTRA_SUPPRESS_SHOW_OVER_APPS = "suppressShowOverApps";
// Flags bitwise-ored to mFlags
private static final int FLAG_AVAILABLE_ON_TV = 0x1;
@@ -8870,6 +8871,7 @@ public class Notification implements Parcelable
private String mChannelId;
private PendingIntent mContentIntent;
private PendingIntent mDeleteIntent;
+ private boolean mSuppressShowOverApps;
/**
* Create a {@link TvExtender} with default options.
@@ -8889,6 +8891,7 @@ public class Notification implements Parcelable
if (bundle != null) {
mFlags = bundle.getInt(EXTRA_FLAGS);
mChannelId = bundle.getString(EXTRA_CHANNEL_ID);
+ mSuppressShowOverApps = bundle.getBoolean(EXTRA_SUPPRESS_SHOW_OVER_APPS);
mContentIntent = bundle.getParcelable(EXTRA_CONTENT_INTENT);
mDeleteIntent = bundle.getParcelable(EXTRA_DELETE_INTENT);
}
@@ -8905,6 +8908,7 @@ public class Notification implements Parcelable
bundle.putInt(EXTRA_FLAGS, mFlags);
bundle.putString(EXTRA_CHANNEL_ID, mChannelId);
+ bundle.putBoolean(EXTRA_SUPPRESS_SHOW_OVER_APPS, mSuppressShowOverApps);
if (mContentIntent != null) {
bundle.putParcelable(EXTRA_CONTENT_INTENT, mContentIntent);
}
@@ -8997,6 +9001,23 @@ public class Notification implements Parcelable
public PendingIntent getDeleteIntent() {
return mDeleteIntent;
}
+
+ /**
+ * Specifies whether this notification should suppress showing a message over top of apps
+ * outside of the launcher.
+ */
+ public TvExtender setSuppressShowOverApps(boolean suppress) {
+ mSuppressShowOverApps = suppress;
+ return this;
+ }
+
+ /**
+ * Returns true if this notification should not show messages over top of apps
+ * outside of the launcher.
+ */
+ public boolean getSuppressShowOverApps() {
+ return mSuppressShowOverApps;
+ }
}
/**
diff --git a/core/java/android/app/ProcessMemoryState.java b/core/java/android/app/ProcessMemoryState.java
new file mode 100644
index 000000000000..39db16d10575
--- /dev/null
+++ b/core/java/android/app/ProcessMemoryState.java
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+package android.app;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * The memory stats for a process.
+ * {@hide}
+ */
+public class ProcessMemoryState implements Parcelable {
+ public int uid;
+ public String processName;
+ public int oomScore;
+ public long pgfault;
+ public long pgmajfault;
+ public long rssInBytes;
+ public long cacheInBytes;
+ public long swapInBytes;
+
+ public ProcessMemoryState(int uid, String processName, int oomScore, long pgfault,
+ long pgmajfault, long rssInBytes, long cacheInBytes,
+ long swapInBytes) {
+ this.uid = uid;
+ this.processName = processName;
+ this.oomScore = oomScore;
+ this.pgfault = pgfault;
+ this.pgmajfault = pgmajfault;
+ this.rssInBytes = rssInBytes;
+ this.cacheInBytes = cacheInBytes;
+ this.swapInBytes = swapInBytes;
+ }
+
+ private ProcessMemoryState(Parcel in) {
+ uid = in.readInt();
+ processName = in.readString();
+ oomScore = in.readInt();
+ pgfault = in.readLong();
+ pgmajfault = in.readLong();
+ rssInBytes = in.readLong();
+ cacheInBytes = in.readLong();
+ swapInBytes = in.readLong();
+ }
+
+ public static final Creator<ProcessMemoryState> CREATOR = new Creator<ProcessMemoryState>() {
+ @Override
+ public ProcessMemoryState createFromParcel(Parcel in) {
+ return new ProcessMemoryState(in);
+ }
+
+ @Override
+ public ProcessMemoryState[] newArray(int size) {
+ return new ProcessMemoryState[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int i) {
+ parcel.writeInt(uid);
+ parcel.writeString(processName);
+ parcel.writeInt(oomScore);
+ parcel.writeLong(pgfault);
+ parcel.writeLong(pgmajfault);
+ parcel.writeLong(rssInBytes);
+ parcel.writeLong(cacheInBytes);
+ parcel.writeLong(swapInBytes);
+ }
+}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index b29644bcf320..14b2119b4e4b 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -21,6 +21,7 @@ import android.annotation.ColorInt;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
@@ -116,6 +117,7 @@ import java.util.concurrent.Executor;
* guide. </div>
*/
@SystemService(Context.DEVICE_POLICY_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_DEVICE_ADMIN)
public class DevicePolicyManager {
private static String TAG = "DevicePolicyManager";
diff --git a/core/java/android/app/admin/FreezeInterval.java b/core/java/android/app/admin/FreezeInterval.java
index 7acdfc8fe100..de5e21ac75c4 100644
--- a/core/java/android/app/admin/FreezeInterval.java
+++ b/core/java/android/app/admin/FreezeInterval.java
@@ -84,6 +84,10 @@ public class FreezeInterval {
}
}
+ boolean after(LocalDate localDate) {
+ return mStartDay > dayOfYearDisregardLeapYear(localDate);
+ }
+
/**
* Instantiate the current interval to real calendar dates, given a calendar date
* {@code now}. If the interval contains now, the returned calendar dates should be the
@@ -161,7 +165,7 @@ public class FreezeInterval {
* 3. At most one wrapped Interval remains, and it will be at the end of the list
* @hide
*/
- private static List<FreezeInterval> canonicalizeIntervals(List<FreezeInterval> intervals) {
+ protected static List<FreezeInterval> canonicalizeIntervals(List<FreezeInterval> intervals) {
boolean[] taken = new boolean[DAYS_IN_YEAR];
// First convert the intervals into flat array
for (FreezeInterval interval : intervals) {
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index 202b89496007..faaa0043cce8 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -78,6 +78,8 @@ public class SecurityLog {
TAG_CERT_AUTHORITY_INSTALLED,
TAG_CERT_AUTHORITY_REMOVED,
TAG_CRYPTO_SELF_TEST_COMPLETED,
+ TAG_KEY_INTEGRITY_VIOLATION,
+ TAG_CERT_VALIDATION_FAILURE,
})
public @interface SecurityLogTag {}
@@ -317,6 +319,7 @@ public class SecurityLog {
* {@link SecurityEvent#getData()}:
* <li> [0] admin package name ({@code String}),
* <li> [1] admin user ID ({@code Integer}).
+ * <li> [2] target user ID ({@code Integer})
*/
public static final int TAG_REMOTE_LOCK = SecurityLogTags.SECURITY_REMOTE_LOCK;
@@ -409,6 +412,23 @@ public class SecurityLog {
SecurityLogTags.SECURITY_CRYPTO_SELF_TEST_COMPLETED;
/**
+ * Indicates a failed cryptographic key integrity check. The log entry contains the following
+ * information about the event, encapsulated in an {@link Object} array and accessible via
+ * {@link SecurityEvent#getData()}:
+ * <li> [0] alias of the key ({@code String})
+ * <li> [1] owner application uid ({@code Integer}).
+ */
+ public static final int TAG_KEY_INTEGRITY_VIOLATION =
+ SecurityLogTags.SECURITY_KEY_INTEGRITY_VIOLATION;
+
+ /**
+ * Indicates a failure to validate X.509v3 certificate. The log entry contains a {@code String}
+ * payload indicating the failure reason, accessible via {@link SecurityEvent#getData()}.
+ */
+ public static final int TAG_CERT_VALIDATION_FAILURE =
+ SecurityLogTags.SECURITY_CERT_VALIDATION_FAILURE;
+
+ /**
* Event severity level indicating that the event corresponds to normal workflow.
*/
public static final int LEVEL_INFO = 1;
@@ -548,7 +568,10 @@ public class SecurityLog {
return getSuccess() ? LEVEL_INFO : LEVEL_WARNING;
case TAG_LOG_BUFFER_SIZE_CRITICAL:
case TAG_WIPE_FAILURE:
+ case TAG_KEY_INTEGRITY_VIOLATION:
return LEVEL_ERROR;
+ case TAG_CERT_VALIDATION_FAILURE:
+ return LEVEL_WARNING;
default:
return LEVEL_INFO;
}
diff --git a/core/java/android/app/admin/SecurityLogTags.logtags b/core/java/android/app/admin/SecurityLogTags.logtags
index b64b7e3e4432..fe2519d2bdf1 100644
--- a/core/java/android/app/admin/SecurityLogTags.logtags
+++ b/core/java/android/app/admin/SecurityLogTags.logtags
@@ -35,4 +35,6 @@ option java_package android.app.admin
210028 security_user_restriction_removed (package|3),(admin_user|1),(restriction|3)
210029 security_cert_authority_installed (success|1),(subject|3)
210030 security_cert_authority_removed (success|1),(subject|3)
-210031 security_crypto_self_test_completed (success|1) \ No newline at end of file
+210031 security_crypto_self_test_completed (success|1)
+210032 security_key_integrity_violation (key_id|3),(uid|1)
+210033 security_cert_validation_failure (reason|3)
diff --git a/core/java/android/app/admin/SystemUpdatePolicy.java b/core/java/android/app/admin/SystemUpdatePolicy.java
index 05d3fd9c632c..47b3a81d0174 100644
--- a/core/java/android/app/admin/SystemUpdatePolicy.java
+++ b/core/java/android/app/admin/SystemUpdatePolicy.java
@@ -21,6 +21,7 @@ import static org.xmlpull.v1.XmlPullParser.END_TAG;
import static org.xmlpull.v1.XmlPullParser.TEXT;
import android.annotation.IntDef;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -33,9 +34,15 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.time.Instant;
import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
import java.util.ArrayList;
+import java.util.Calendar;
import java.util.List;
+import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
@@ -103,6 +110,19 @@ public class SystemUpdatePolicy implements Parcelable {
*/
public static final int TYPE_POSTPONE = 3;
+ /**
+ * Incoming system updates (including security updates) should be blocked. This flag is not
+ * exposed to third-party apps (and any attempt to set it will raise exceptions). This is used
+ * to represent the current installation option type to the privileged system update clients,
+ * for example to indicate OTA freeze is currently in place or when system is outside a daily
+ * maintenance window.
+ *
+ * @see InstallationOption
+ * @hide
+ */
+ @SystemApi
+ public static final int TYPE_PAUSE = 4;
+
private static final String KEY_POLICY_TYPE = "policy_type";
private static final String KEY_INSTALL_WINDOW_START = "install_window_start";
private static final String KEY_INSTALL_WINDOW_END = "install_window_end";
@@ -460,6 +480,30 @@ public class SystemUpdatePolicy implements Parcelable {
return null;
}
+ /**
+ * Returns time (in milliseconds) until the start of the next freeze period, assuming now
+ * is not within a freeze period.
+ */
+ private long timeUntilNextFreezePeriod(long now) {
+ List<FreezeInterval> sortedPeriods = FreezeInterval.canonicalizeIntervals(mFreezePeriods);
+ LocalDate nowDate = millisToDate(now);
+ LocalDate nextFreezeStart = null;
+ for (FreezeInterval interval : sortedPeriods) {
+ if (interval.after(nowDate)) {
+ nextFreezeStart = interval.toCurrentOrFutureRealDates(nowDate).first;
+ break;
+ } else if (interval.contains(nowDate)) {
+ throw new IllegalArgumentException("Given date is inside a freeze period");
+ }
+ }
+ if (nextFreezeStart == null) {
+ // If no interval is after now, then it must be the one that starts at the beginning
+ // of next year
+ nextFreezeStart = sortedPeriods.get(0).toCurrentOrFutureRealDates(nowDate).first;
+ }
+ return dateToMillis(nextFreezeStart) - now;
+ }
+
/** @hide */
public void validateFreezePeriods() {
FreezeInterval.validatePeriods(mFreezePeriods);
@@ -472,6 +516,134 @@ public class SystemUpdatePolicy implements Parcelable {
prevPeriodEnd, now);
}
+ /**
+ * An installation option represents how system update clients should act on incoming system
+ * updates and how long this action is valid for, given the current system update policy. Its
+ * action could be one of the following
+ * <ul>
+ * <li> {@code TYPE_INSTALL_AUTOMATIC} system updates should be installed immedately and without
+ * user intervention as soon as they become available.
+ * <li> {@code TYPE_POSTPONE} system updates should be postponed for a maximum of 30 days
+ * <li> {@code TYPE_PAUSE} system updates should be postponed indefinitely until further notice
+ * </ul>
+ *
+ * The effective time measures how long this installation option is valid for from the queried
+ * time, in milliseconds.
+ *
+ * This is an internal API for system update clients.
+ * @hide
+ */
+ @SystemApi
+ public static class InstallationOption {
+ private final int mType;
+ private long mEffectiveTime;
+
+ InstallationOption(int type, long effectiveTime) {
+ this.mType = type;
+ this.mEffectiveTime = effectiveTime;
+ }
+
+ public int getType() {
+ return mType;
+ }
+
+ public long getEffectiveTime() {
+ return mEffectiveTime;
+ }
+
+ /** @hide */
+ protected void limitEffectiveTime(long otherTime) {
+ mEffectiveTime = Long.min(mEffectiveTime, otherTime);
+ }
+ }
+
+ /**
+ * Returns the installation option at the specified time, under the current
+ * {@code SystemUpdatePolicy} object. This is a convenience method for system update clients
+ * so they can instantiate this policy at any given time and find out what to do with incoming
+ * system updates, without the need of examining the overall policy structure.
+ *
+ * Normally the system update clients will query the current installation option by calling this
+ * method with the current timestamp, and act on the returned option until its effective time
+ * lapses. It can then query the latest option using a new timestamp. It should also listen
+ * for {@code DevicePolicyManager#ACTION_SYSTEM_UPDATE_POLICY_CHANGED} broadcast, in case the
+ * whole policy is updated.
+ *
+ * @param when At what time the intallation option is being queried, specified in number of
+ milliseonds since the epoch.
+ * @see InstallationOption
+ * @hide
+ */
+ @SystemApi
+ public InstallationOption getInstallationOptionAt(long when) {
+ LocalDate whenDate = millisToDate(when);
+ Pair<LocalDate, LocalDate> current = getCurrentFreezePeriod(whenDate);
+ if (current != null) {
+ return new InstallationOption(TYPE_PAUSE,
+ dateToMillis(roundUpLeapDay(current.second).plusDays(1)) - when);
+ }
+ // We are not within a freeze period, query the underlying policy.
+ // But also consider the start of the next freeze period, which might
+ // reduce the effective time of the current installation option
+ InstallationOption option = getInstallationOptionRegardlessFreezeAt(when);
+ if (mFreezePeriods.size() > 0) {
+ option.limitEffectiveTime(timeUntilNextFreezePeriod(when));
+ }
+ return option;
+ }
+
+ private InstallationOption getInstallationOptionRegardlessFreezeAt(long when) {
+ if (mPolicyType == TYPE_INSTALL_AUTOMATIC || mPolicyType == TYPE_POSTPONE) {
+ return new InstallationOption(mPolicyType, Long.MAX_VALUE);
+ } else if (mPolicyType == TYPE_INSTALL_WINDOWED) {
+ Calendar query = Calendar.getInstance();
+ query.setTimeInMillis(when);
+ // Calculate the number of milliseconds since midnight of the time specified by when
+ long whenMillis = TimeUnit.HOURS.toMillis(query.get(Calendar.HOUR_OF_DAY))
+ + TimeUnit.MINUTES.toMillis(query.get(Calendar.MINUTE))
+ + TimeUnit.SECONDS.toMillis(query.get(Calendar.SECOND))
+ + query.get(Calendar.MILLISECOND);
+ long windowStartMillis = TimeUnit.MINUTES.toMillis(mMaintenanceWindowStart);
+ long windowEndMillis = TimeUnit.MINUTES.toMillis(mMaintenanceWindowEnd);
+ final long dayInMillis = TimeUnit.DAYS.toMillis(1);
+
+ if ((windowStartMillis <= whenMillis && whenMillis <= windowEndMillis)
+ || ((windowStartMillis > windowEndMillis)
+ && (windowStartMillis <= whenMillis || whenMillis <= windowEndMillis))) {
+ return new InstallationOption(TYPE_INSTALL_AUTOMATIC,
+ (windowEndMillis - whenMillis + dayInMillis) % dayInMillis);
+ } else {
+ return new InstallationOption(TYPE_PAUSE,
+ (windowStartMillis - whenMillis + dayInMillis) % dayInMillis);
+ }
+ } else {
+ throw new RuntimeException("Unknown policy type");
+ }
+ }
+
+ private static LocalDate roundUpLeapDay(LocalDate date) {
+ if (date.isLeapYear() && date.getMonthValue() == 2 && date.getDayOfMonth() == 28) {
+ return date.plusDays(1);
+ } else {
+ return date;
+ }
+ }
+
+ /** Convert a timestamp since epoch to a LocalDate using default timezone, truncating
+ * the hour/min/seconds part.
+ */
+ private static LocalDate millisToDate(long when) {
+ return Instant.ofEpochMilli(when).atZone(ZoneId.systemDefault()).toLocalDate();
+ }
+
+ /**
+ * Returns the timestamp since epoch of a LocalDate, assuming the time is 00:00:00.
+ */
+ private static long dateToMillis(LocalDate when) {
+ return LocalDateTime.of(when, LocalTime.MIN).atZone(ZoneId.systemDefault()).toInstant()
+ .toEpochMilli();
+ }
+
@Override
public String toString() {
return String.format("SystemUpdatePolicy (type: %d, windowStart: %d, windowEnd: %d, "
@@ -480,11 +652,13 @@ public class SystemUpdatePolicy implements Parcelable {
mFreezePeriods.stream().map(n -> n.toString()).collect(Collectors.joining(",")));
}
+ @SystemApi
@Override
public int describeContents() {
return 0;
}
+ @SystemApi
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mPolicyType);
@@ -499,6 +673,7 @@ public class SystemUpdatePolicy implements Parcelable {
}
}
+ @SystemApi
public static final Parcelable.Creator<SystemUpdatePolicy> CREATOR =
new Parcelable.Creator<SystemUpdatePolicy>() {
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 0f1c249faf83..1312a2e6b623 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -1303,6 +1303,17 @@ public class AssistStructure implements Parcelable {
}
/**
+ * @hide
+ */
+ public void setWebDomain(@Nullable String domain) {
+ if (domain == null) return;
+
+ final Uri uri = Uri.parse(domain);
+ mWebScheme = uri.getScheme();
+ mWebDomain = uri.getHost();
+ }
+
+ /**
* Returns the scheme of the HTML document represented by this view.
*
* <p>Typically used when the view associated with the view is a container for an HTML
@@ -1889,14 +1900,7 @@ public class AssistStructure implements Parcelable {
@Override
public void setWebDomain(@Nullable String domain) {
- if (domain == null) {
- mNode.mWebScheme = null;
- mNode.mWebDomain = null;
- return;
- }
- Uri uri = Uri.parse(domain);
- mNode.mWebScheme = uri.getScheme();
- mNode.mWebDomain = uri.getHost();
+ mNode.setWebDomain(domain);
}
@Override
diff --git a/core/java/android/app/backup/OWNERS b/core/java/android/app/backup/OWNERS
new file mode 100644
index 000000000000..1c9a43acfa65
--- /dev/null
+++ b/core/java/android/app/backup/OWNERS
@@ -0,0 +1,7 @@
+artikz@google.com
+brufino@google.com
+bryanmawhinney@google.com
+ctate@google.com
+jorlow@google.com
+mkarpinski@google.com
+
diff --git a/core/java/android/app/servertransaction/ActivityLifecycleItem.java b/core/java/android/app/servertransaction/ActivityLifecycleItem.java
index 9a50a009ce34..7f8c50cd4ce5 100644
--- a/core/java/android/app/servertransaction/ActivityLifecycleItem.java
+++ b/core/java/android/app/servertransaction/ActivityLifecycleItem.java
@@ -91,4 +91,9 @@ public abstract class ActivityLifecycleItem extends ClientTransactionItem {
pw.println(prefix + "target state:" + getTargetState());
pw.println(prefix + "description: " + mDescription);
}
+
+ @Override
+ public void recycle() {
+ setDescription(null);
+ }
}
diff --git a/core/java/android/app/servertransaction/DestroyActivityItem.java b/core/java/android/app/servertransaction/DestroyActivityItem.java
index 48a79f79dae1..0edcf1884f01 100644
--- a/core/java/android/app/servertransaction/DestroyActivityItem.java
+++ b/core/java/android/app/servertransaction/DestroyActivityItem.java
@@ -65,6 +65,7 @@ public class DestroyActivityItem extends ActivityLifecycleItem {
@Override
public void recycle() {
+ super.recycle();
mFinished = false;
mConfigChanges = 0;
ObjectPool.recycle(this);
diff --git a/core/java/android/app/servertransaction/PauseActivityItem.java b/core/java/android/app/servertransaction/PauseActivityItem.java
index 70a4755f99af..91e73cd5b1cd 100644
--- a/core/java/android/app/servertransaction/PauseActivityItem.java
+++ b/core/java/android/app/servertransaction/PauseActivityItem.java
@@ -102,6 +102,7 @@ public class PauseActivityItem extends ActivityLifecycleItem {
@Override
public void recycle() {
+ super.recycle();
mFinished = false;
mUserLeaving = false;
mConfigChanges = 0;
diff --git a/core/java/android/app/servertransaction/ResumeActivityItem.java b/core/java/android/app/servertransaction/ResumeActivityItem.java
index ed90f2cb1013..af2fb713e1bc 100644
--- a/core/java/android/app/servertransaction/ResumeActivityItem.java
+++ b/core/java/android/app/servertransaction/ResumeActivityItem.java
@@ -101,6 +101,7 @@ public class ResumeActivityItem extends ActivityLifecycleItem {
@Override
public void recycle() {
+ super.recycle();
mProcState = ActivityManager.PROCESS_STATE_UNKNOWN;
mUpdateProcState = false;
mIsForward = false;
diff --git a/core/java/android/app/servertransaction/StopActivityItem.java b/core/java/android/app/servertransaction/StopActivityItem.java
index b814d1ae1392..f955a903d649 100644
--- a/core/java/android/app/servertransaction/StopActivityItem.java
+++ b/core/java/android/app/servertransaction/StopActivityItem.java
@@ -72,6 +72,7 @@ public class StopActivityItem extends ActivityLifecycleItem {
@Override
public void recycle() {
+ super.recycle();
mShowWindow = false;
mConfigChanges = 0;
ObjectPool.recycle(this);
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index a2c75a6c014c..e736f34eea11 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -19,6 +19,7 @@ package android.appwidget;
import android.annotation.BroadcastBehavior;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemService;
@@ -29,6 +30,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.ShortcutInfo;
import android.os.Bundle;
@@ -55,6 +57,7 @@ import java.util.List;
* </div>
*/
@SystemService(Context.APPWIDGET_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_APP_WIDGETS)
public class AppWidgetManager {
/**
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index bc7823b00f49..1dc7549e763a 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2307,6 +2307,9 @@ public final class BluetoothAdapter {
} else if (profile == BluetoothProfile.HID_DEVICE) {
BluetoothHidDevice hidDevice = new BluetoothHidDevice(context, listener);
return true;
+ } else if (profile == BluetoothProfile.HEARING_AID) {
+ BluetoothHearingAid hearingAid = new BluetoothHearingAid(context, listener);
+ return true;
} else {
return false;
}
@@ -2389,6 +2392,9 @@ public final class BluetoothAdapter {
BluetoothHidDevice hidDevice = (BluetoothHidDevice) proxy;
hidDevice.close();
break;
+ case BluetoothProfile.HEARING_AID:
+ BluetoothHearingAid hearingAid = (BluetoothHearingAid) proxy;
+ hearingAid.close();
}
}
diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java
new file mode 100644
index 000000000000..647e0d033fb7
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHearingAid.java
@@ -0,0 +1,693 @@
+/*
+ * Copyright 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.
+ */
+
+package android.bluetooth;
+
+import android.Manifest;
+import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * This class provides the public APIs to control the Bluetooth Hearing Aid
+ * profile.
+ *
+ * <p>BluetoothHearingAid is a proxy object for controlling the Bluetooth Hearing Aid
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothHearingAid proxy object.
+ *
+ * <p> Each method is protected with its appropriate permission.
+ * @hide
+ */
+public final class BluetoothHearingAid implements BluetoothProfile {
+ private static final String TAG = "BluetoothHearingAid";
+ private static final boolean DBG = false;
+ private static final boolean VDBG = false;
+
+ /**
+ * Intent used to broadcast the change in connection state of the Hearing Aid
+ * profile.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
+ * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_CONNECTION_STATE_CHANGED =
+ "android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED";
+
+ /**
+ * Intent used to broadcast the change in the Playing state of the Hearing Aid
+ * profile.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING},
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PLAYING_STATE_CHANGED =
+ "android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED";
+
+ /**
+ * Intent used to broadcast the selection of a connected device as active.
+ *
+ * <p>This intent will have one extra:
+ * <ul>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
+ * be null if no device is active. </li>
+ * </ul>
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_ACTIVE_DEVICE_CHANGED =
+ "android.bluetooth.hearingaid.profile.action.ACTIVE_DEVICE_CHANGED";
+
+ /**
+ * Hearing Aid device is streaming music. This state can be one of
+ * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
+ * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
+ */
+ public static final int STATE_PLAYING = 10;
+
+ /**
+ * Hearing Aid device is NOT streaming music. This state can be one of
+ * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
+ * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
+ */
+ public static final int STATE_NOT_PLAYING = 11;
+
+ /** This device represents Left Hearing Aid. */
+ public static final int SIDE_LEFT = IBluetoothHearingAid.SIDE_LEFT;
+
+ /** This device represents Right Hearing Aid. */
+ public static final int SIDE_RIGHT = IBluetoothHearingAid.SIDE_RIGHT;
+
+ /** This device is Monaural. */
+ public static final int MODE_MONAURAL = IBluetoothHearingAid.MODE_MONAURAL;
+
+ /** This device is Binaural (should receive only left or right audio). */
+ public static final int MODE_BINAURAL = IBluetoothHearingAid.MODE_BINAURAL;
+
+ /** Can't read ClientID for this device */
+ public static final long HI_SYNC_ID_INVALID = IBluetoothHearingAid.HI_SYNC_ID_INVALID;
+
+ private Context mContext;
+ private ServiceListener mServiceListener;
+ private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
+ @GuardedBy("mServiceLock")
+ private IBluetoothHearingAid mService;
+ private BluetoothAdapter mAdapter;
+
+ private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+ public void onBluetoothStateChange(boolean up) {
+ if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+ if (!up) {
+ if (VDBG) Log.d(TAG, "Unbinding service...");
+ try {
+ mServiceLock.writeLock().lock();
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG, "", re);
+ } finally {
+ mServiceLock.writeLock().unlock();
+ }
+ } else {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService == null) {
+ if (VDBG) Log.d(TAG, "Binding service...");
+ doBind();
+ }
+ } catch (Exception re) {
+ Log.e(TAG, "", re);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+ }
+ };
+
+ /**
+ * Create a BluetoothHearingAid proxy object for interacting with the local
+ * Bluetooth Hearing Aid service.
+ */
+ /*package*/ BluetoothHearingAid(Context context, ServiceListener l) {
+ mContext = context;
+ mServiceListener = l;
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+
+ doBind();
+ }
+
+ void doBind() {
+ Intent intent = new Intent(IBluetoothHearingAid.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+ android.os.Process.myUserHandle())) {
+ Log.e(TAG, "Could not bind to Bluetooth Hearing Aid Service with " + intent);
+ return;
+ }
+ }
+
+ /*package*/ void close() {
+ mServiceListener = null;
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (Exception e) {
+ Log.e(TAG, "", e);
+ }
+ }
+
+ try {
+ mServiceLock.writeLock().lock();
+ if (mService != null) {
+ mService = null;
+ mContext.unbindService(mConnection);
+ }
+ } catch (Exception re) {
+ Log.e(TAG, "", re);
+ } finally {
+ mServiceLock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public void finalize() {
+ // The empty finalize needs to be kept or the
+ // cts signature tests would fail.
+ }
+
+ /**
+ * Initiate connection to a profile of the remote bluetooth device.
+ *
+ * <p> This API returns false in scenarios like the profile on the
+ * device is already connected or Bluetooth is not turned on.
+ * When this API returns true, it is guaranteed that
+ * connection state intent for the profile will be broadcasted with
+ * the state. Users can get the connection state of the profile
+ * from this intent.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * permission.
+ *
+ * @param device Remote Bluetooth Device
+ * @return false on immediate error, true otherwise
+ * @hide
+ */
+ public boolean connect(BluetoothDevice device) {
+ if (DBG) log("connect(" + device + ")");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled() && isValidDevice(device)) {
+ return mService.connect(device);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Initiate disconnection from a profile
+ *
+ * <p> This API will return false in scenarios like the profile on the
+ * Bluetooth device is not in connected state etc. When this API returns,
+ * true, it is guaranteed that the connection state change
+ * intent will be broadcasted with the state. Users can get the
+ * disconnection state of the profile from this intent.
+ *
+ * <p> If the disconnection is initiated by a remote device, the state
+ * will transition from {@link #STATE_CONNECTED} to
+ * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
+ * host (local) device the state will transition from
+ * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
+ * state {@link #STATE_DISCONNECTED}. The transition to
+ * {@link #STATE_DISCONNECTING} can be used to distinguish between the
+ * two scenarios.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * permission.
+ *
+ * @param device Remote Bluetooth Device
+ * @return false on immediate error, true otherwise
+ * @hide
+ */
+ public boolean disconnect(BluetoothDevice device) {
+ if (DBG) log("disconnect(" + device + ")");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled() && isValidDevice(device)) {
+ return mService.disconnect(device);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (VDBG) log("getConnectedDevices()");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()) {
+ return mService.getConnectedDevices();
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ if (VDBG) log("getDevicesMatchingStates()");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()) {
+ return mService.getDevicesMatchingConnectionStates(states);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getConnectionState(BluetoothDevice device) {
+ if (VDBG) log("getState(" + device + ")");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ return mService.getConnectionState(device);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Set priority of the profile
+ *
+ * <p> The device should already be paired.
+ * Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
+ * {@link #PRIORITY_OFF},
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * permission.
+ *
+ * @param device Paired bluetooth device
+ * @param priority
+ * @return true if priority is set, false on error
+ * @hide
+ */
+ public boolean setPriority(BluetoothDevice device, int priority) {
+ if (DBG) log("setPriority(" + device + ", " + priority + ")");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ if (priority != BluetoothProfile.PRIORITY_OFF
+ && priority != BluetoothProfile.PRIORITY_ON) {
+ return false;
+ }
+ return mService.setPriority(device, priority);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Get the priority of the profile.
+ *
+ * <p> The priority can be any of:
+ * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
+ * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
+ *
+ * @param device Bluetooth device
+ * @return priority of the device
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public int getPriority(BluetoothDevice device) {
+ if (VDBG) log("getPriority(" + device + ")");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ return mService.getPriority(device);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.PRIORITY_OFF;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.PRIORITY_OFF;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Helper for converting a state to a string.
+ *
+ * For debug use only - strings are not internationalized.
+ *
+ * @hide
+ */
+ public static String stateToString(int state) {
+ switch (state) {
+ case STATE_DISCONNECTED:
+ return "disconnected";
+ case STATE_CONNECTING:
+ return "connecting";
+ case STATE_CONNECTED:
+ return "connected";
+ case STATE_DISCONNECTING:
+ return "disconnecting";
+ case STATE_PLAYING:
+ return "playing";
+ case STATE_NOT_PLAYING:
+ return "not playing";
+ default:
+ return "<unknown state " + state + ">";
+ }
+ }
+
+ /**
+ * Get the volume of the device.
+ *
+ * <p> The volume is between -128 dB (mute) to 0 dB.
+ *
+ * @return volume of the hearing aid device.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public int getVolume() {
+ if (VDBG) {
+ log("getVolume()");
+ }
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()) {
+ return mService.getVolume();
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return 0;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return 0;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Tells remote device to adjust volume. Uses the following values:
+ * <ul>
+ * <li>{@link AudioManager#ADJUST_LOWER}</li>
+ * <li>{@link AudioManager#ADJUST_RAISE}</li>
+ * <li>{@link AudioManager#ADJUST_MUTE}</li>
+ * <li>{@link AudioManager#ADJUST_UNMUTE}</li>
+ * </ul>
+ *
+ * @param direction One of the supported adjust values.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public void adjustVolume(int direction) {
+ if (DBG) log("adjustVolume(" + direction + ")");
+
+ try {
+ mServiceLock.readLock().lock();
+
+ if (mService == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ return;
+ }
+
+ if (!isEnabled()) return;
+
+ mService.adjustVolume(direction);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Tells remote device to set an absolute volume.
+ *
+ * @param volume Absolute volume to be set on remote
+ * @hide
+ */
+ public void setVolume(int volume) {
+ if (DBG) Log.d(TAG, "setVolume(" + volume + ")");
+
+ try {
+ mServiceLock.readLock().lock();
+ if (mService == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ return;
+ }
+
+ if (!isEnabled()) return;
+
+ mService.setVolume(volume);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Get the CustomerId of the device.
+ *
+ * @param device Bluetooth device
+ * @return the CustomerId of the device
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public long getHiSyncId(BluetoothDevice device) {
+ if (VDBG) {
+ log("getCustomerId(" + device + ")");
+ }
+ try {
+ mServiceLock.readLock().lock();
+ if (mService == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ return HI_SYNC_ID_INVALID;
+ }
+
+ if (!isEnabled() || !isValidDevice(device)) return HI_SYNC_ID_INVALID;
+
+ return mService.getHiSyncId(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return HI_SYNC_ID_INVALID;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Get the side of the device.
+ *
+ * @param device Bluetooth device.
+ * @return SIDE_LEFT or SIDE_RIGHT
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public int getDeviceSide(BluetoothDevice device) {
+ if (VDBG) {
+ log("getDeviceSide(" + device + ")");
+ }
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ return mService.getDeviceSide(device);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return SIDE_LEFT;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return SIDE_LEFT;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Get the mode of the device.
+ *
+ * @param device Bluetooth device
+ * @return MODE_MONAURAL or MODE_BINAURAL
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public int getDeviceMode(BluetoothDevice device) {
+ if (VDBG) {
+ log("getDeviceMode(" + device + ")");
+ }
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ return mService.getDeviceMode(device);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return MODE_MONAURAL;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return MODE_MONAURAL;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ private final ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ if (DBG) Log.d(TAG, "Proxy object connected");
+ try {
+ mServiceLock.writeLock().lock();
+ mService = IBluetoothHearingAid.Stub.asInterface(Binder.allowBlocking(service));
+ } finally {
+ mServiceLock.writeLock().unlock();
+ }
+
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.HEARING_AID,
+ BluetoothHearingAid.this);
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ if (DBG) Log.d(TAG, "Proxy object disconnected");
+ try {
+ mServiceLock.writeLock().lock();
+ mService = null;
+ } finally {
+ mServiceLock.writeLock().unlock();
+ }
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.HEARING_AID);
+ }
+ }
+ };
+
+ private boolean isEnabled() {
+ if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
+ return false;
+ }
+
+ private boolean isValidDevice(BluetoothDevice device) {
+ if (device == null) return false;
+
+ if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+ return false;
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index 7e3bb05fe024..11f8ab7551c2 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -17,9 +17,11 @@
package android.bluetooth;
import android.Manifest;
+import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.RemoteException;
import android.util.Log;
@@ -47,6 +49,7 @@ import java.util.List;
* @see BluetoothAdapter#getDefaultAdapter()
*/
@SystemService(Context.BLUETOOTH_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_BLUETOOTH)
public final class BluetoothManager {
private static final String TAG = "BluetoothManager";
private static final boolean DBG = true;
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 0e2263f773b8..656188fbdfb8 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -165,12 +165,19 @@ public interface BluetoothProfile {
public static final int OPP = 20;
/**
+ * Hearing Aid Device
+ *
+ * @hide
+ */
+ int HEARING_AID = 21;
+
+ /**
* Max profile ID. This value should be updated whenever a new profile is added to match
* the largest value assigned to a profile.
*
* @hide
*/
- public static final int MAX_PROFILE_ID = 20;
+ int MAX_PROFILE_ID = 21;
/**
* Default priority for devices that we try to auto-connect to and
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 76cb3f5b548e..0a0d21498032 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -79,6 +79,9 @@ public final class BluetoothUuid {
ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid SAP =
ParcelUuid.fromString("0000112D-0000-1000-8000-00805F9B34FB");
+ /* TODO: b/69623109 update this value. It will change to 16bit UUID!! */
+ public static final ParcelUuid HearingAid =
+ ParcelUuid.fromString("7312C48F-22CC-497F-85FD-A0616A3B9E05");
public static final ParcelUuid BASE_UUID =
ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index a788989a7578..b072ee622ad9 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1000,7 +1000,7 @@ public class ContextWrapper extends Context {
*/
@Override
public boolean isAutofillCompatibilityEnabled() {
- return mBase.isAutofillCompatibilityEnabled();
+ return mBase != null && mBase.isAutofillCompatibilityEnabled();
}
/**
@@ -1008,6 +1008,8 @@ public class ContextWrapper extends Context {
*/
@Override
public void setAutofillCompatibilityEnabled(boolean autofillCompatEnabled) {
- mBase.setAutofillCompatibilityEnabled(autofillCompatEnabled);
+ if (mBase != null) {
+ mBase.setAutofillCompatibilityEnabled(autofillCompatEnabled);
+ }
}
}
diff --git a/core/java/android/content/om/IOverlayManager.aidl b/core/java/android/content/om/IOverlayManager.aidl
index 86c1aa8228f1..5b3c9dd93370 100644
--- a/core/java/android/content/om/IOverlayManager.aidl
+++ b/core/java/android/content/om/IOverlayManager.aidl
@@ -83,17 +83,36 @@ interface IOverlayManager {
* @param packageName The name of the overlay package.
* @param enable true to enable the overlay, false to disable it.
* @param userId The user for which to change the overlay.
- * @return true if the system successfully registered the request, false
- * otherwise.
+ * @return true if the system successfully registered the request, false otherwise.
*/
boolean setEnabled(in String packageName, in boolean enable, in int userId);
/**
- * Version of setEnabled that will also disable any other overlays for the target package.
+ * Request that an overlay package is enabled and any other overlay packages with the same
+ * target package are disabled.
+ *
+ * See {@link #setEnabled} for the details on overlay packages.
+ *
+ * @param packageName the name of the overlay package to enable.
+ * @param enabled must be true, otherwise the operation fails.
+ * @param userId The user for which to change the overlay.
+ * @return true if the system successfully registered the request, false otherwise.
*/
boolean setEnabledExclusive(in String packageName, in boolean enable, in int userId);
/**
+ * Request that an overlay package is enabled and any other overlay packages with the same
+ * target package and category are disabled.
+ *
+ * See {@link #setEnabled} for the details on overlay packages.
+ *
+ * @param packageName the name of the overlay package to enable.
+ * @param userId The user for which to change the overlay.
+ * @return true if the system successfully registered the request, false otherwise.
+ */
+ boolean setEnabledExclusiveInCategory(in String packageName, in int userId);
+
+ /**
* Change the priority of the given overlay to be just higher than the
* overlay with package name newParentPackageName. Both overlay packages
* must have the same target and user.
diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java
index 8464e26ec6cd..6e63342698b3 100644
--- a/core/java/android/content/om/OverlayInfo.java
+++ b/core/java/android/content/om/OverlayInfo.java
@@ -18,6 +18,7 @@ package android.content.om;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -66,14 +67,14 @@ public final class OverlayInfo implements Parcelable {
/**
* The overlay is currently disabled. It can be enabled.
*
- * @see IOverlayManager.setEnabled
+ * @see IOverlayManager#setEnabled
*/
public static final int STATE_DISABLED = 2;
/**
* The overlay is currently enabled. It can be disabled.
*
- * @see IOverlayManager.setEnabled
+ * @see IOverlayManager#setEnabled
*/
public static final int STATE_ENABLED = 3;
@@ -90,6 +91,11 @@ public final class OverlayInfo implements Parcelable {
public static final int STATE_OVERLAY_UPGRADING = 5;
/**
+ * Category for theme overlays.
+ */
+ public static final String CATEGORY_THEME = "android.theme";
+
+ /**
* Package name of the overlay package
*/
public final String packageName;
@@ -100,6 +106,11 @@ public final class OverlayInfo implements Parcelable {
public final String targetPackageName;
/**
+ * Category of the overlay package
+ */
+ public final String category;
+
+ /**
* Full path to the base APK for this overlay package
*/
public final String baseCodePath;
@@ -121,14 +132,15 @@ public final class OverlayInfo implements Parcelable {
* @param state the new state for the source OverlayInfo
*/
public OverlayInfo(@NonNull OverlayInfo source, @State int state) {
- this(source.packageName, source.targetPackageName, source.baseCodePath, state,
- source.userId);
+ this(source.packageName, source.targetPackageName, source.category, source.baseCodePath,
+ state, source.userId);
}
public OverlayInfo(@NonNull String packageName, @NonNull String targetPackageName,
- @NonNull String baseCodePath, @State int state, int userId) {
+ @Nullable String category, @NonNull String baseCodePath, int state, int userId) {
this.packageName = packageName;
this.targetPackageName = targetPackageName;
+ this.category = category;
this.baseCodePath = baseCodePath;
this.state = state;
this.userId = userId;
@@ -138,6 +150,7 @@ public final class OverlayInfo implements Parcelable {
public OverlayInfo(Parcel source) {
packageName = source.readString();
targetPackageName = source.readString();
+ category = source.readString();
baseCodePath = source.readString();
state = source.readInt();
userId = source.readInt();
@@ -177,6 +190,7 @@ public final class OverlayInfo implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(packageName);
dest.writeString(targetPackageName);
+ dest.writeString(category);
dest.writeString(baseCodePath);
dest.writeInt(state);
dest.writeInt(userId);
@@ -275,6 +289,9 @@ public final class OverlayInfo implements Parcelable {
if (!targetPackageName.equals(other.targetPackageName)) {
return false;
}
+ if (!category.equals(other.category)) {
+ return false;
+ }
if (!baseCodePath.equals(other.baseCodePath)) {
return false;
}
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 0342c93bb34f..627ceb7871f2 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -362,6 +362,13 @@ public class PackageInfo implements Parcelable {
*/
public String overlayTarget;
+ /**
+ * The overlay category, if any, of this package
+ *
+ * @hide
+ */
+ public String overlayCategory;
+
/** @hide */
public int overlayPriority;
@@ -464,6 +471,7 @@ public class PackageInfo implements Parcelable {
dest.writeString(restrictedAccountType);
dest.writeString(requiredAccountType);
dest.writeString(overlayTarget);
+ dest.writeString(overlayCategory);
dest.writeInt(overlayPriority);
dest.writeBoolean(mOverlayIsStatic);
dest.writeInt(compileSdkVersion);
@@ -531,6 +539,7 @@ public class PackageInfo implements Parcelable {
restrictedAccountType = source.readString();
requiredAccountType = source.readString();
overlayTarget = source.readString();
+ overlayCategory = source.readString();
overlayPriority = source.readInt();
mOverlayIsStatic = source.readBoolean();
compileSdkVersion = source.readInt();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 08fccab6a5b2..07a991188a49 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2070,6 +2070,15 @@ public abstract class PackageManager {
"android.hardware.sensor.hifi_sensors";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+ * The device supports a hardware mechanism for invoking an assist gesture.
+ * @see android.provider.Settings.Secure#ASSIST_GESTURE_ENABLED
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_ASSIST_GESTURE = "android.hardware.sensor.assist";
+
+ /**
* Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device has a telephony radio with data
* communication support.
@@ -5065,6 +5074,7 @@ public abstract class PackageManager {
* which market the package came from.
*
* @param packageName The name of the package to query
+ * @throws IllegalArgumentException if the given package name is not installed
*/
public abstract String getInstallerPackageName(String packageName);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index dda4167d3c3b..9e4166eaec1b 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -676,6 +676,7 @@ public class PackageParser {
pi.restrictedAccountType = p.mRestrictedAccountType;
pi.requiredAccountType = p.mRequiredAccountType;
pi.overlayTarget = p.mOverlayTarget;
+ pi.overlayCategory = p.mOverlayCategory;
pi.overlayPriority = p.mOverlayPriority;
pi.mOverlayIsStatic = p.mOverlayIsStatic;
pi.compileSdkVersion = p.mCompileSdkVersion;
@@ -2073,6 +2074,8 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestResourceOverlay);
pkg.mOverlayTarget = sa.getString(
com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage);
+ pkg.mOverlayCategory = sa.getString(
+ com.android.internal.R.styleable.AndroidManifestResourceOverlay_category);
pkg.mOverlayPriority = sa.getInt(
com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority,
0);
@@ -6324,6 +6327,7 @@ public class PackageParser {
public String mRequiredAccountType;
public String mOverlayTarget;
+ public String mOverlayCategory;
public int mOverlayPriority;
public boolean mOverlayIsStatic;
@@ -6834,6 +6838,7 @@ public class PackageParser {
mRestrictedAccountType = dest.readString();
mRequiredAccountType = dest.readString();
mOverlayTarget = dest.readString();
+ mOverlayCategory = dest.readString();
mOverlayPriority = dest.readInt();
mOverlayIsStatic = (dest.readInt() == 1);
mCompileSdkVersion = dest.readInt();
@@ -6957,6 +6962,7 @@ public class PackageParser {
dest.writeString(mRestrictedAccountType);
dest.writeString(mRequiredAccountType);
dest.writeString(mOverlayTarget);
+ dest.writeString(mOverlayCategory);
dest.writeInt(mOverlayPriority);
dest.writeInt(mOverlayIsStatic ? 1 : 0);
dest.writeInt(mCompileSdkVersion);
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index cf0145123b87..424fa833cd48 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -27,9 +27,11 @@ import android.annotation.StyleRes;
import android.annotation.StyleableRes;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo.Config;
+import android.content.res.AssetManager.AssetInputStream;
import android.content.res.Configuration.NativeConfig;
import android.content.res.Resources.NotFoundException;
import android.graphics.Bitmap;
+import android.graphics.ImageDecoder;
import android.graphics.Typeface;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -752,6 +754,26 @@ public class ResourcesImpl {
}
/**
+ * Loads a Drawable from an encoded image stream, or null.
+ *
+ * This call will handle closing ais.
+ */
+ private Drawable decodeImageDrawable(@NonNull AssetInputStream ais,
+ @NonNull Resources wrapper, @NonNull TypedValue value) {
+ ImageDecoder.Source src = new ImageDecoder.AssetInputStreamSource(ais,
+ wrapper, value);
+ try {
+ return ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
+ decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+ });
+ } catch (IOException ioe) {
+ // This is okay. This may be something that ImageDecoder does not
+ // support, like SVG.
+ return null;
+ }
+ }
+
+ /**
* Loads a drawable from XML or resources stream.
*/
@NonNull
@@ -811,8 +833,8 @@ public class ResourcesImpl {
} else {
final InputStream is = mAssets.openNonAsset(
value.assetCookie, file, AssetManager.ACCESS_STREAMING);
- dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
- is.close();
+ AssetInputStream ais = (AssetInputStream) is;
+ dr = decodeImageDrawable(ais, wrapper, value);
}
} finally {
stack.pop();
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index a2991e6e9cb6..64e9e5db7c4b 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -58,7 +58,7 @@ public abstract class SQLiteOpenHelper {
private SQLiteDatabase mDatabase;
private boolean mIsInitializing;
- private final SQLiteDatabase.OpenParams.Builder mOpenParamsBuilder;
+ private SQLiteDatabase.OpenParams.Builder mOpenParamsBuilder;
/**
* Create a helper object to create, open, and/or manage a database.
@@ -163,8 +163,7 @@ public abstract class SQLiteOpenHelper {
mName = name;
mNewVersion = version;
mMinimumSupportedVersion = Math.max(0, minimumSupportedVersion);
- mOpenParamsBuilder = openParamsBuilder;
- mOpenParamsBuilder.addOpenFlags(SQLiteDatabase.CREATE_IF_NECESSARY);
+ setOpenParamsBuilder(openParamsBuilder);
}
/**
@@ -230,6 +229,30 @@ public abstract class SQLiteOpenHelper {
}
/**
+ * Sets configuration parameters that are used for opening {@link SQLiteDatabase}.
+ * <p>Please note that {@link SQLiteDatabase#CREATE_IF_NECESSARY} flag will always be set when
+ * opening the database
+ *
+ * @param openParams configuration parameters that are used for opening {@link SQLiteDatabase}.
+ * @throws IllegalStateException if the database is already open
+ */
+ public void setOpenParams(@NonNull SQLiteDatabase.OpenParams openParams) {
+ Preconditions.checkNotNull(openParams);
+ synchronized (this) {
+ if (mDatabase != null && mDatabase.isOpen()) {
+ throw new IllegalStateException(
+ "OpenParams cannot be set after opening the database");
+ }
+ setOpenParamsBuilder(new SQLiteDatabase.OpenParams.Builder(openParams));
+ }
+ }
+
+ private void setOpenParamsBuilder(SQLiteDatabase.OpenParams.Builder openParamsBuilder) {
+ mOpenParamsBuilder = openParamsBuilder;
+ mOpenParamsBuilder.addOpenFlags(SQLiteDatabase.CREATE_IF_NECESSARY);
+ }
+
+ /**
* Sets the maximum number of milliseconds that SQLite connection is allowed to be idle
* before it is closed and removed from the pool.
*
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 931b5c913851..f08e1cc24b26 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -242,6 +242,9 @@ public class Camera {
/**
* Returns the number of physical cameras available on this device.
+ * The return value of this method might change dynamically if the device
+ * supports external cameras and an external camera is connected or
+ * disconnected.
*
* @return total number of accessible camera devices, or 0 if there are no
* cameras or an error was encountered enumerating them.
@@ -3542,8 +3545,8 @@ public class Camera {
/**
* Gets the horizontal angle of view in degrees.
*
- * @return horizontal angle of view. This method will always return a
- * valid value.
+ * @return horizontal angle of view. Returns -1.0 when the device
+ * doesn't report view angle information.
*/
public float getHorizontalViewAngle() {
return Float.parseFloat(get(KEY_HORIZONTAL_VIEW_ANGLE));
@@ -3552,8 +3555,8 @@ public class Camera {
/**
* Gets the vertical angle of view in degrees.
*
- * @return vertical angle of view. This method will always return a
- * valid value.
+ * @return vertical angle of view. Returns -1.0 when the device
+ * doesn't report view angle information.
*/
public float getVerticalViewAngle() {
return Float.parseFloat(get(KEY_VERTICAL_VIEW_ANGLE));
diff --git a/core/java/android/hardware/ConsumerIrManager.java b/core/java/android/hardware/ConsumerIrManager.java
index c7a33ffa1b0f..6f589cd9190b 100644
--- a/core/java/android/hardware/ConsumerIrManager.java
+++ b/core/java/android/hardware/ConsumerIrManager.java
@@ -16,8 +16,10 @@
package android.hardware;
+import android.annotation.RequiresFeature;
import android.annotation.SystemService;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
@@ -27,6 +29,7 @@ import android.util.Log;
* Class that operates consumer infrared on the device.
*/
@SystemService(Context.CONSUMER_IR_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_CONSUMER_IR)
public final class ConsumerIrManager {
private static final String TAG = "ConsumerIr";
diff --git a/core/java/android/hardware/OWNERS b/core/java/android/hardware/OWNERS
new file mode 100644
index 000000000000..b8fea556e4c5
--- /dev/null
+++ b/core/java/android/hardware/OWNERS
@@ -0,0 +1,7 @@
+# Camera
+per-file *Camera* = cychen@google.com
+per-file *Camera* = epeev@google.com
+per-file *Camera* = etalvala@google.com
+per-file *Camera* = shuzhenwang@google.com
+per-file *Camera* = yinchiayeh@google.com
+per-file *Camera* = zhijunhe@google.com
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 3f8eaa902cb2..8502fc413c05 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -341,7 +341,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
*/
@SuppressWarnings({"unchecked"})
public List<CaptureRequest.Key<?>> getAvailablePhysicalCameraRequestKeys() {
- if (mAvailableSessionKeys == null) {
+ if (mAvailablePhysicalRequestKeys == null) {
Object crKey = CaptureRequest.Key.class;
Class<CaptureRequest.Key<?>> crKeyTyped = (Class<CaptureRequest.Key<?>>)crKey;
@@ -1790,11 +1790,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* The respective value of such request key can be obtained by calling
* {@link CaptureRequest.Builder#getPhysicalCameraKey }. Capture requests that contain
* individual physical device requests must be built via
- * {@link android.hardware.camera2.CameraDevice#createCaptureRequest(int, Set)}.
- * Such extended capture requests can be passed only to
- * {@link CameraCaptureSession#capture } or {@link CameraCaptureSession#captureBurst } and
- * not to {@link CameraCaptureSession#setRepeatingRequest } or
- * {@link CameraCaptureSession#setRepeatingBurst }.</p>
+ * {@link android.hardware.camera2.CameraDevice#createCaptureRequest(int, Set)}.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* <p><b>Limited capability</b> -
* Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index fd285aef864f..72db33f90c20 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -863,11 +863,8 @@ public abstract class CameraDevice implements AutoCloseable {
* request for a specific physical camera. The settings are chosen
* to be the best options for the specific logical camera device. If
* additional physical camera ids are passed, then they will also use the
- * same settings template. Requests containing individual physical camera
- * settings can be passed only to {@link CameraCaptureSession#capture} or
- * {@link CameraCaptureSession#captureBurst} and not to
- * {@link CameraCaptureSession#setRepeatingRequest} or
- * {@link CameraCaptureSession#setRepeatingBurst}</p>
+ * same settings template. Clients can further modify individual camera
+ * settings by calling {@link CaptureRequest.Builder#setPhysicalCameraKey}.</p>
*
* <p>Individual physical camera settings will only be honored for camera session
* that was initialiazed with corresponding physical camera id output configuration
@@ -896,8 +893,8 @@ public abstract class CameraDevice implements AutoCloseable {
* @see #TEMPLATE_STILL_CAPTURE
* @see #TEMPLATE_VIDEO_SNAPSHOT
* @see #TEMPLATE_MANUAL
- * @see CaptureRequest.Builder#setKey
- * @see CaptureRequest.Builder#getKey
+ * @see CaptureRequest.Builder#setPhysicalCameraKey
+ * @see CaptureRequest.Builder#getPhysicalCameraKey
*/
@NonNull
public CaptureRequest.Builder createCaptureRequest(@RequestTemplate int templateType,
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 732f6a519781..e558b7e29a20 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -829,19 +829,24 @@ public abstract class CameraMetadata<TKey> {
* <li>{@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}</li>
* </ul>
* </li>
+ * <li>The SENSOR_INFO_TIMESTAMP_SOURCE of the logical device and physical devices must be
+ * the same.</li>
* <li>The logical camera device must be LIMITED or higher device.</li>
* </ul>
* <p>Both the logical camera device and its underlying physical devices support the
* mandatory stream combinations required for their device levels.</p>
* <p>Additionally, for each guaranteed stream combination, the logical camera supports:</p>
* <ul>
- * <li>Replacing one logical {@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888}
+ * <li>For each guaranteed stream combination, the logical camera supports replacing one
+ * logical {@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888}
* or raw stream with two physical streams of the same size and format, each from a
* separate physical camera, given that the size and format are supported by both
* physical cameras.</li>
- * <li>Adding two raw streams, each from one physical camera, if the logical camera doesn't
- * advertise RAW capability, but the underlying physical cameras do. This is usually
- * the case when the physical cameras have different sensor sizes.</li>
+ * <li>If the logical camera doesn't advertise RAW capability, but the underlying physical
+ * cameras do, the logical camera will support guaranteed stream combinations for RAW
+ * capability, except that the RAW streams will be physical streams, each from a separate
+ * physical camera. This is usually the case when the physical cameras have different
+ * sensor sizes.</li>
* </ul>
* <p>Using physical streams in place of a logical stream of the same size and format will
* not slow down the frame rate of the capture, as long as the minimum frame duration
diff --git a/core/java/android/hardware/camera2/OWNERS b/core/java/android/hardware/camera2/OWNERS
new file mode 100644
index 000000000000..18acfee14555
--- /dev/null
+++ b/core/java/android/hardware/camera2/OWNERS
@@ -0,0 +1,6 @@
+cychen@google.com
+epeev@google.com
+etalvala@google.com
+shuzhenwang@google.com
+yinchiayeh@google.com
+zhijunhe@google.com
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index b205e2c7649d..a040a09cf469 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -82,11 +82,9 @@ import java.util.List;
*
* </ul>
*
- * <p>Please note that surface sharing is currently only enabled for outputs that use the
- * {@link ImageFormat#PRIVATE} format. This includes surface sources like
- * {@link android.view.SurfaceView}, {@link android.media.MediaRecorder},
- * {@link android.graphics.SurfaceTexture} and {@link android.media.ImageReader}, configured using
- * the aforementioned format.</p>
+ * <p> As of {@link android.os.Build.VERSION_CODES#P Android P}, all formats can be used for
+ * sharing, subject to device support. On prior API levels, only {@link ImageFormat#PRIVATE}
+ * format may be used.</p>
*
* @see CameraDevice#createCaptureSessionByOutputConfigurations
*
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 92d6bbb0a20f..bd54522719b2 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -23,10 +23,12 @@ import static android.Manifest.permission.USE_FINGERPRINT;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.app.ActivityManager;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricFingerprintConstants;
import android.os.Binder;
@@ -59,6 +61,7 @@ import javax.crypto.Mac;
*/
@Deprecated
@SystemService(Context.FINGERPRINT_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_FINGERPRINT)
public class FingerprintManager implements BiometricFingerprintConstants {
private static final String TAG = "FingerprintManager";
private static final boolean DEBUG = true;
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index a772cbe43196..e34423c05a87 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -17,11 +17,13 @@
package android.hardware.hdmi;
import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SuppressLint;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.os.RemoteException;
@@ -42,6 +44,7 @@ import android.util.Log;
*/
@SystemApi
@SystemService(Context.HDMI_CONTROL_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_HDMI_CEC)
public final class HdmiControlManager {
private static final String TAG = "HdmiControlManager";
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java
index e1d7edfa7d9c..8fde82ef2012 100644
--- a/core/java/android/hardware/radio/RadioManager.java
+++ b/core/java/android/hardware/radio/RadioManager.java
@@ -21,10 +21,12 @@ import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
@@ -58,6 +60,7 @@ import java.util.stream.Collectors;
*/
@SystemApi
@SystemService(Context.RADIO_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_BROADCAST_RADIO)
public class RadioManager {
private static final String TAG = "BroadcastRadio.manager";
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index 5b15c0d2fd9c..9e5174ad93a8 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -222,7 +222,10 @@ public class UsbDeviceConnection {
* @param endpoint the endpoint for this transaction
* @param buffer buffer for data to send or receive; can be {@code null} to wait for next
* transaction without reading data
- * @param length the length of the data to send or receive
+ * @param length the length of the data to send or receive. Before
+ * {@value Build.VERSION_CODES#P}, a value larger than 16384 bytes
+ * would be truncated down to 16384. In API {@value Build.VERSION_CODES#P}
+ * and after, any value of length is valid.
* @param timeout in milliseconds, 0 is infinite
* @return length of data transferred (or zero) for success,
* or negative value for failure
@@ -239,7 +242,10 @@ public class UsbDeviceConnection {
* @param endpoint the endpoint for this transaction
* @param buffer buffer for data to send or receive
* @param offset the index of the first byte in the buffer to send or receive
- * @param length the length of the data to send or receive
+ * @param length the length of the data to send or receive. Before
+ * {@value Build.VERSION_CODES#P}, a value larger than 16384 bytes
+ * would be truncated down to 16384. In API {@value Build.VERSION_CODES#P}
+ * and after, any value of length is valid.
* @param timeout in milliseconds, 0 is infinite
* @return length of data transferred (or zero) for success,
* or negative value for failure
@@ -247,6 +253,10 @@ public class UsbDeviceConnection {
public int bulkTransfer(UsbEndpoint endpoint,
byte[] buffer, int offset, int length, int timeout) {
checkBounds(buffer, offset, length);
+ if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P
+ && length > UsbRequest.MAX_USBFS_BUFFER_SIZE) {
+ length = UsbRequest.MAX_USBFS_BUFFER_SIZE;
+ }
return native_bulk_request(endpoint.getAddress(), buffer, offset, length, timeout);
}
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 8daecac5a109..74a36df03b00 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -19,6 +19,7 @@ package android.hardware.usb;
import android.Manifest;
import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
@@ -27,6 +28,7 @@ import android.annotation.SystemService;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.hardware.usb.gadget.V1_0.GadgetFunction;
import android.os.Bundle;
@@ -382,6 +384,7 @@ public class UsbManager {
*
* @return HashMap containing all connected USB devices.
*/
+ @RequiresFeature(PackageManager.FEATURE_USB_HOST)
public HashMap<String,UsbDevice> getDeviceList() {
HashMap<String,UsbDevice> result = new HashMap<String,UsbDevice>();
if (mService == null) {
@@ -406,6 +409,7 @@ public class UsbManager {
* @param device the device to open
* @return a {@link UsbDeviceConnection}, or {@code null} if open failed
*/
+ @RequiresFeature(PackageManager.FEATURE_USB_HOST)
public UsbDeviceConnection openDevice(UsbDevice device) {
try {
String deviceName = device.getDeviceName();
@@ -430,6 +434,7 @@ public class UsbManager {
*
* @return list of USB accessories, or null if none are attached.
*/
+ @RequiresFeature(PackageManager.FEATURE_USB_ACCESSORY)
public UsbAccessory[] getAccessoryList() {
if (mService == null) {
return null;
@@ -452,6 +457,7 @@ public class UsbManager {
* @param accessory the USB accessory to open
* @return file descriptor, or null if the accessor could not be opened.
*/
+ @RequiresFeature(PackageManager.FEATURE_USB_ACCESSORY)
public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
try {
return mService.openAccessory(accessory);
@@ -472,6 +478,7 @@ public class UsbManager {
* @param device to check permissions for
* @return true if caller has permission
*/
+ @RequiresFeature(PackageManager.FEATURE_USB_HOST)
public boolean hasPermission(UsbDevice device) {
if (mService == null) {
return false;
@@ -492,6 +499,7 @@ public class UsbManager {
* @param accessory to check permissions for
* @return true if caller has permission
*/
+ @RequiresFeature(PackageManager.FEATURE_USB_ACCESSORY)
public boolean hasPermission(UsbAccessory accessory) {
if (mService == null) {
return false;
@@ -525,6 +533,7 @@ public class UsbManager {
* @param device to request permissions for
* @param pi PendingIntent for returning result
*/
+ @RequiresFeature(PackageManager.FEATURE_USB_HOST)
public void requestPermission(UsbDevice device, PendingIntent pi) {
try {
mService.requestDevicePermission(device, mContext.getPackageName(), pi);
@@ -551,6 +560,7 @@ public class UsbManager {
* @param accessory to request permissions for
* @param pi PendingIntent for returning result
*/
+ @RequiresFeature(PackageManager.FEATURE_USB_ACCESSORY)
public void requestPermission(UsbAccessory accessory, PendingIntent pi) {
try {
mService.requestAccessoryPermission(accessory, mContext.getPackageName(), pi);
diff --git a/core/java/android/hardware/usb/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java
index 2e8f8e12b508..f59c87eecfcb 100644
--- a/core/java/android/hardware/usb/UsbRequest.java
+++ b/core/java/android/hardware/usb/UsbRequest.java
@@ -17,6 +17,7 @@
package android.hardware.usb;
import android.annotation.Nullable;
+import android.os.Build;
import android.util.Log;
import com.android.internal.util.Preconditions;
@@ -43,7 +44,7 @@ public class UsbRequest {
private static final String TAG = "UsbRequest";
// From drivers/usb/core/devio.c
- private static final int MAX_USBFS_BUFFER_SIZE = 16384;
+ static final int MAX_USBFS_BUFFER_SIZE = 16384;
// used by the JNI code
private long mNativeContext;
@@ -175,7 +176,9 @@ public class UsbRequest {
* capacity will be ignored. Once the request
* {@link UsbDeviceConnection#requestWait() is processed} the position will be set
* to the number of bytes read/written.
- * @param length number of bytes to read or write.
+ * @param length number of bytes to read or write. Before {@value Build.VERSION_CODES#P}, a
+ * value larger than 16384 bytes would be truncated down to 16384. In API
+ * {@value Build.VERSION_CODES#P} and after, any value of length is valid.
*
* @return true if the queueing operation succeeded
*
@@ -186,6 +189,11 @@ public class UsbRequest {
boolean out = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
boolean result;
+ if (mConnection.getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P
+ && length > MAX_USBFS_BUFFER_SIZE) {
+ length = MAX_USBFS_BUFFER_SIZE;
+ }
+
synchronized (mLock) {
// save our buffer for when the request has completed
mBuffer = buffer;
@@ -222,7 +230,10 @@ public class UsbRequest {
* of the buffer is undefined until the request is returned by
* {@link UsbDeviceConnection#requestWait}. If the request failed the buffer
* will be unchanged; if the request succeeded the position of the buffer is
- * incremented by the number of bytes sent/received.
+ * incremented by the number of bytes sent/received. Before
+ * {@value Build.VERSION_CODES#P}, a buffer of length larger than 16384 bytes
+ * would throw IllegalArgumentException. In API {@value Build.VERSION_CODES#P}
+ * and after, any size buffer is valid.
*
* @return true if the queueing operation succeeded
*/
@@ -244,9 +255,12 @@ public class UsbRequest {
mIsUsingNewQueue = true;
wasQueued = native_queue(null, 0, 0);
} else {
- // Can only send/receive MAX_USBFS_BUFFER_SIZE bytes at once
- Preconditions.checkArgumentInRange(buffer.remaining(), 0, MAX_USBFS_BUFFER_SIZE,
- "number of remaining bytes");
+ if (mConnection.getContext().getApplicationInfo().targetSdkVersion
+ < Build.VERSION_CODES.P) {
+ // Can only send/receive MAX_USBFS_BUFFER_SIZE bytes at once
+ Preconditions.checkArgumentInRange(buffer.remaining(), 0, MAX_USBFS_BUFFER_SIZE,
+ "number of remaining bytes");
+ }
// Can not receive into read-only buffers.
Preconditions.checkArgument(!(buffer.isReadOnly() && !isSend), "buffer can not be "
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 166342dd4e6d..91c99be32c98 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -112,8 +112,14 @@ public class ConnectivityManager {
* <p/>
* For a disconnect event, the boolean extra EXTRA_NO_CONNECTIVITY
* is set to {@code true} if there are no connected networks at all.
+ *
+ * @deprecated apps should use the more versatile {@link #requestNetwork},
+ * {@link #registerNetworkCallback} or {@link #registerDefaultNetworkCallback}
+ * functions instead for faster and more detailed updates about the network
+ * changes they care about.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @Deprecated
public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
/**
@@ -2656,7 +2662,7 @@ public class ConnectivityManager {
* A {@code NetworkCallback} is registered by calling
* {@link #requestNetwork(NetworkRequest, NetworkCallback)},
* {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)},
- * or {@link #registerDefaultNetworkCallback(NetworkCallback). A {@code NetworkCallback} is
+ * or {@link #registerDefaultNetworkCallback(NetworkCallback)}. A {@code NetworkCallback} is
* unregistered by calling {@link #unregisterNetworkCallback(NetworkCallback)}.
* A {@code NetworkCallback} should be registered at most once at any time.
* A {@code NetworkCallback} that has been unregistered can be registered again.
@@ -2685,6 +2691,32 @@ public class ConnectivityManager {
* satisfying the request changes.
*
* @param network The {@link Network} of the satisfying network.
+ * @param networkCapabilities The {@link NetworkCapabilities} of the satisfying network.
+ * @param linkProperties The {@link LinkProperties} of the satisfying network.
+ * @hide
+ */
+ public void onAvailable(Network network, NetworkCapabilities networkCapabilities,
+ LinkProperties linkProperties) {
+ // Internally only this method is called when a new network is available, and
+ // it calls the callback in the same way and order that older versions used
+ // to call so as not to change the behavior.
+ onAvailable(network);
+ if (!networkCapabilities.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)) {
+ onNetworkSuspended(network);
+ }
+ onCapabilitiesChanged(network, networkCapabilities);
+ onLinkPropertiesChanged(network, linkProperties);
+ }
+
+ /**
+ * Called when the framework connects and has declared a new network ready for use.
+ * This callback may be called more than once if the {@link Network} that is
+ * satisfying the request changes. This will always immediately be followed by a
+ * call to {@link #onCapabilitiesChanged(Network, NetworkCapabilities)} then by a
+ * call to {@link #onLinkPropertiesChanged(Network, LinkProperties)}.
+ *
+ * @param network The {@link Network} of the satisfying network.
*/
public void onAvailable(Network network) {}
@@ -2727,7 +2759,8 @@ public class ConnectivityManager {
* changes capabilities but still satisfies the stated need.
*
* @param network The {@link Network} whose capabilities have changed.
- * @param networkCapabilities The new {@link android.net.NetworkCapabilities} for this network.
+ * @param networkCapabilities The new {@link android.net.NetworkCapabilities} for this
+ * network.
*/
public void onCapabilitiesChanged(Network network,
NetworkCapabilities networkCapabilities) {}
@@ -2743,7 +2776,7 @@ public class ConnectivityManager {
/**
* Called when the network the framework connected to for this request
- * goes into {@link NetworkInfo.DetailedState.SUSPENDED}.
+ * goes into {@link NetworkInfo.State#SUSPENDED}.
* This generally means that while the TCP connections are still live,
* temporarily network data fails to transfer. Specifically this is used
* on cellular networks to mask temporary outages when driving through
@@ -2754,9 +2787,8 @@ public class ConnectivityManager {
/**
* Called when the network the framework connected to for this request
- * returns from a {@link NetworkInfo.DetailedState.SUSPENDED} state.
- * This should always be preceeded by a matching {@code onNetworkSuspended}
- * call.
+ * returns from a {@link NetworkInfo.State#SUSPENDED} state. This should always be
+ * preceded by a matching {@link NetworkCallback#onNetworkSuspended} call.
* @hide
*/
public void onNetworkResumed(Network network) {}
@@ -2865,7 +2897,9 @@ public class ConnectivityManager {
break;
}
case CALLBACK_AVAILABLE: {
- callback.onAvailable(network);
+ NetworkCapabilities cap = getObject(message, NetworkCapabilities.class);
+ LinkProperties lp = getObject(message, LinkProperties.class);
+ callback.onAvailable(network, cap, lp);
break;
}
case CALLBACK_LOSING: {
diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java
index 6a262e2c87ca..8599f47c6245 100644
--- a/core/java/android/net/IpSecConfig.java
+++ b/core/java/android/net/IpSecConfig.java
@@ -218,6 +218,25 @@ public final class IpSecConfig implements Parcelable {
@VisibleForTesting
public IpSecConfig() {}
+ /** Copy constructor */
+ @VisibleForTesting
+ public IpSecConfig(IpSecConfig c) {
+ mMode = c.mMode;
+ mSourceAddress = c.mSourceAddress;
+ mDestinationAddress = c.mDestinationAddress;
+ mNetwork = c.mNetwork;
+ mSpiResourceId = c.mSpiResourceId;
+ mEncryption = c.mEncryption;
+ mAuthentication = c.mAuthentication;
+ mAuthenticatedEncryption = c.mAuthenticatedEncryption;
+ mEncapType = c.mEncapType;
+ mEncapSocketResourceId = c.mEncapSocketResourceId;
+ mEncapRemotePort = c.mEncapRemotePort;
+ mNattKeepaliveInterval = c.mNattKeepaliveInterval;
+ mMarkValue = c.mMarkValue;
+ mMarkMask = c.mMarkMask;
+ }
+
private IpSecConfig(Parcel in) {
mMode = in.readInt();
mSourceAddress = in.readString();
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index 38759a9183f2..60e96f943401 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -84,9 +84,11 @@ public final class IpSecTransform implements AutoCloseable {
@Retention(RetentionPolicy.SOURCE)
public @interface EncapType {}
- private IpSecTransform(Context context, IpSecConfig config) {
+ /** @hide */
+ @VisibleForTesting
+ public IpSecTransform(Context context, IpSecConfig config) {
mContext = context;
- mConfig = config;
+ mConfig = new IpSecConfig(config);
mResourceId = INVALID_RESOURCE_ID;
}
@@ -143,6 +145,18 @@ public final class IpSecTransform implements AutoCloseable {
}
/**
+ * Equals method used for testing
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public static boolean equals(IpSecTransform lhs, IpSecTransform rhs) {
+ if (lhs == null || rhs == null) return (lhs == rhs);
+ return IpSecConfig.equals(lhs.getConfig(), rhs.getConfig())
+ && lhs.mResourceId == rhs.mResourceId;
+ }
+
+ /**
* Deactivate this {@code IpSecTransform} and free allocated resources.
*
* <p>Deactivating a transform while it is still applied to a socket will result in errors on
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 8e05cfa96625..bae373d7564b 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -116,6 +116,7 @@ public final class NetworkCapabilities implements Parcelable {
NET_CAPABILITY_NOT_ROAMING,
NET_CAPABILITY_FOREGROUND,
NET_CAPABILITY_NOT_CONGESTED,
+ NET_CAPABILITY_NOT_SUSPENDED,
})
public @interface NetCapability { }
@@ -239,7 +240,6 @@ public final class NetworkCapabilities implements Parcelable {
/**
* Indicates that this network is available for use by apps, and not a network that is being
* kept up in the background to facilitate fast network switching.
- * @hide
*/
public static final int NET_CAPABILITY_FOREGROUND = 19;
@@ -252,8 +252,20 @@ public final class NetworkCapabilities implements Parcelable {
*/
public static final int NET_CAPABILITY_NOT_CONGESTED = 20;
+ /**
+ * Indicates that this network is not currently suspended.
+ * <p>
+ * When a network is suspended, the network's IP addresses and any connections
+ * established on the network remain valid, but the network is temporarily unable
+ * to transfer data. This can happen, for example, if a cellular network experiences
+ * a temporary loss of signal, such as when driving through a tunnel, etc.
+ * A network with this capability is not suspended, so is expected to be able to
+ * transfer data.
+ */
+ public static final int NET_CAPABILITY_NOT_SUSPENDED = 21;
+
private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
- private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_CONGESTED;
+ private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_SUSPENDED;
/**
* Network capabilities that are expected to be mutable, i.e., can change while a particular
@@ -262,12 +274,13 @@ public final class NetworkCapabilities implements Parcelable {
private static final long MUTABLE_CAPABILITIES =
// TRUSTED can change when user explicitly connects to an untrusted network in Settings.
// http://b/18206275
- (1 << NET_CAPABILITY_TRUSTED) |
- (1 << NET_CAPABILITY_VALIDATED) |
- (1 << NET_CAPABILITY_CAPTIVE_PORTAL) |
- (1 << NET_CAPABILITY_NOT_ROAMING) |
- (1 << NET_CAPABILITY_FOREGROUND) |
- (1 << NET_CAPABILITY_NOT_CONGESTED);
+ (1 << NET_CAPABILITY_TRUSTED)
+ | (1 << NET_CAPABILITY_VALIDATED)
+ | (1 << NET_CAPABILITY_CAPTIVE_PORTAL)
+ | (1 << NET_CAPABILITY_NOT_ROAMING)
+ | (1 << NET_CAPABILITY_FOREGROUND)
+ | (1 << NET_CAPABILITY_NOT_CONGESTED)
+ | (1 << NET_CAPABILITY_NOT_SUSPENDED);
/**
* Network capabilities that are not allowed in NetworkRequests. This exists because the
@@ -1299,6 +1312,7 @@ public final class NetworkCapabilities implements Parcelable {
case NET_CAPABILITY_NOT_ROAMING: return "NOT_ROAMING";
case NET_CAPABILITY_FOREGROUND: return "FOREGROUND";
case NET_CAPABILITY_NOT_CONGESTED: return "NOT_CONGESTED";
+ case NET_CAPABILITY_NOT_SUSPENDED: return "NOT_SUSPENDED";
default: return Integer.toString(capability);
}
}
diff --git a/core/java/android/net/OWNERS b/core/java/android/net/OWNERS
index 3a40cf4bf8a3..3cd37bf4fbdd 100644
--- a/core/java/android/net/OWNERS
+++ b/core/java/android/net/OWNERS
@@ -1,3 +1,5 @@
+set noparent
+
ek@google.com
jsharkey@android.com
jchalard@google.com
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 5d7cf1e3899f..7cd58e8b7c36 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2240,12 +2240,16 @@ public abstract class BatteryStats implements Parcelable {
public static final int DATA_CONNECTION_LTE = 13;
public static final int DATA_CONNECTION_EHRPD = 14;
public static final int DATA_CONNECTION_HSPAP = 15;
- public static final int DATA_CONNECTION_OTHER = 16;
+ public static final int DATA_CONNECTION_GSM = 16;
+ public static final int DATA_CONNECTION_TD_SCDMA = 17;
+ public static final int DATA_CONNECTION_IWLAN = 18;
+ public static final int DATA_CONNECTION_LTE_CA = 19;
+ public static final int DATA_CONNECTION_OTHER = 20;
static final String[] DATA_CONNECTION_NAMES = {
"none", "gprs", "edge", "umts", "cdma", "evdo_0", "evdo_A",
"1xrtt", "hsdpa", "hsupa", "hspa", "iden", "evdo_b", "lte",
- "ehrpd", "hspap", "other"
+ "ehrpd", "hspap", "gsm", "td_scdma", "iwlan", "lte_ca", "other"
};
public static final int NUM_DATA_CONNECTION_TYPES = DATA_CONNECTION_OTHER+1;
diff --git a/core/java/android/os/BestClock.java b/core/java/android/os/BestClock.java
new file mode 100644
index 000000000000..aa066b633e6b
--- /dev/null
+++ b/core/java/android/os/BestClock.java
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+package android.os;
+
+import android.util.Log;
+
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.ZoneId;
+import java.util.Arrays;
+
+/**
+ * Single {@link Clock} that will return the best available time from a set of
+ * prioritized {@link Clock} instances.
+ * <p>
+ * For example, when {@link SystemClock#currentNetworkTimeClock()} isn't able to
+ * provide the time, this class could use {@link Clock#systemUTC()} instead.
+ *
+ * @hide
+ */
+public class BestClock extends SimpleClock {
+ private static final String TAG = "BestClock";
+
+ private final Clock[] clocks;
+
+ public BestClock(ZoneId zone, Clock... clocks) {
+ super(zone);
+ this.clocks = clocks;
+ }
+
+ @Override
+ public long millis() {
+ for (Clock clock : clocks) {
+ try {
+ return clock.millis();
+ } catch (DateTimeException e) {
+ // Ignore and attempt the next clock
+ Log.w(TAG, e.toString());
+ }
+ }
+ throw new DateTimeException(
+ "No clocks in " + Arrays.toString(clocks) + " were able to provide time");
+ }
+}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 682fdb7160f4..ff7c0c6681c6 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -1028,22 +1028,33 @@ final class BinderProxy implements IBinder {
* in use, then we return the same bp.
*
* @param nativeData C++ pointer to (possibly still empty) BinderProxyNativeData.
- * Takes ownership of nativeData iff <result>.mNativeData == nativeData. Caller will usually
- * delete nativeData if that's not the case.
+ * Takes ownership of nativeData iff <result>.mNativeData == nativeData, or if
+ * we exit via an exception. If neither applies, it's the callers responsibility to
+ * recycle nativeData.
* @param iBinder C++ pointer to IBinder. Does not take ownership of referenced object.
*/
private static BinderProxy getInstance(long nativeData, long iBinder) {
- BinderProxy result = sProxyMap.get(iBinder);
- if (result == null) {
+ BinderProxy result;
+ try {
+ result = sProxyMap.get(iBinder);
+ if (result != null) {
+ return result;
+ }
result = new BinderProxy(nativeData);
- sProxyMap.set(iBinder, result);
+ } catch (Throwable e) {
+ // We're throwing an exception (probably OOME); don't drop nativeData.
+ NativeAllocationRegistry.applyFreeFunction(NoImagePreloadHolder.sNativeFinalizer,
+ nativeData);
+ throw e;
}
+ NoImagePreloadHolder.sRegistry.registerNativeAllocation(result, nativeData);
+ // The registry now owns nativeData, even if registration threw an exception.
+ sProxyMap.set(iBinder, result);
return result;
}
private BinderProxy(long nativeData) {
mNativeData = nativeData;
- NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeData);
}
/**
@@ -1057,8 +1068,9 @@ final class BinderProxy implements IBinder {
// Use a Holder to allow static initialization of BinderProxy in the boot image, and
// to avoid some initialization ordering issues.
private static class NoImagePreloadHolder {
+ public static final long sNativeFinalizer = getNativeFinalizer();
public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
- BinderProxy.class.getClassLoader(), getNativeFinalizer(), NATIVE_ALLOCATION_SIZE);
+ BinderProxy.class.getClassLoader(), sNativeFinalizer, NATIVE_ALLOCATION_SIZE);
}
public native boolean pingBinder();
diff --git a/core/java/android/os/ChildZygoteProcess.java b/core/java/android/os/ChildZygoteProcess.java
new file mode 100644
index 000000000000..337a3e279a1a
--- /dev/null
+++ b/core/java/android/os/ChildZygoteProcess.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+package android.os;
+
+import android.net.LocalSocketAddress;
+
+/**
+ * Represents a connection to a child-zygote process. A child-zygote is spawend from another
+ * zygote process using {@link startChildZygote()}.
+ *
+ * {@hide}
+ */
+public class ChildZygoteProcess extends ZygoteProcess {
+ /**
+ * The PID of the child zygote process.
+ */
+ private final int mPid;
+
+ ChildZygoteProcess(LocalSocketAddress socketAddress, int pid) {
+ super(socketAddress, null);
+ mPid = pid;
+ }
+
+ /**
+ * Returns the PID of the child-zygote process.
+ */
+ public int getPid() {
+ return mPid;
+ }
+}
diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java
index cdee1101c27b..228fe7a3dae5 100644
--- a/core/java/android/os/HwBinder.java
+++ b/core/java/android/os/HwBinder.java
@@ -29,7 +29,13 @@ public abstract class HwBinder implements IHwBinder {
private static final NativeAllocationRegistry sNativeRegistry;
- /** @hide */
+ /**
+ * Create and initialize a HwBinder object and the native objects
+ * used to allow this to participate in hwbinder transactions.
+ *
+ * @hide
+ */
+ @SystemApi
public HwBinder() {
native_setup();
@@ -44,12 +50,28 @@ public abstract class HwBinder implements IHwBinder {
int code, HwParcel request, HwParcel reply, int flags)
throws RemoteException;
- /** @hide */
+ /**
+ * Process a hwbinder transaction.
+ *
+ * @param code interface specific code for interface.
+ * @param request parceled transaction
+ * @param reply object to parcel reply into
+ * @param flags transaction flags to be chosen by wire protocol
+ *
+ * @hide
+ */
+ @SystemApi
public abstract void onTransact(
int code, HwParcel request, HwParcel reply, int flags)
throws RemoteException;
- /** @hide */
+ /**
+ * Registers this service with the hwservicemanager.
+ *
+ * @param serviceName instance name of the service
+ * @hide
+ */
+ @SystemApi
public native final void registerService(String serviceName)
throws RemoteException;
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 65e9473380ce..5e23932c48cc 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -71,6 +71,7 @@ interface IUserManager {
Bundle getUserRestrictions(int userHandle);
boolean hasBaseUserRestriction(String restrictionKey, int userHandle);
boolean hasUserRestriction(in String restrictionKey, int userHandle);
+ boolean hasUserRestrictionOnAnyUser(in String restrictionKey);
void setUserRestriction(String key, boolean value, int userHandle);
void setApplicationRestrictions(in String packageName, in Bundle restrictions,
int userHandle);
diff --git a/core/java/android/os/SimpleClock.java b/core/java/android/os/SimpleClock.java
new file mode 100644
index 000000000000..efc271f5408f
--- /dev/null
+++ b/core/java/android/os/SimpleClock.java
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package android.os;
+
+import java.time.Clock;
+import java.time.Instant;
+import java.time.ZoneId;
+
+/** {@hide} */
+public abstract class SimpleClock extends Clock {
+ private final ZoneId zone;
+
+ public SimpleClock(ZoneId zone) {
+ this.zone = zone;
+ }
+
+ @Override
+ public ZoneId getZone() {
+ return zone;
+ }
+
+ @Override
+ public Clock withZone(ZoneId zone) {
+ return new SimpleClock(zone) {
+ @Override
+ public long millis() {
+ return SimpleClock.this.millis();
+ }
+ };
+ }
+
+ @Override
+ public abstract long millis();
+
+ @Override
+ public Instant instant() {
+ return Instant.ofEpochMilli(millis());
+ }
+}
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index c52c22d60ade..0f70427e6dc0 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -24,8 +24,7 @@ import android.util.Slog;
import dalvik.annotation.optimization.CriticalNative;
import java.time.Clock;
-import java.time.Instant;
-import java.time.ZoneId;
+import java.time.DateTimeException;
import java.time.ZoneOffset;
/**
@@ -148,8 +147,8 @@ public final class SystemClock {
* @return if the clock was successfully set to the specified time.
*/
public static boolean setCurrentTimeMillis(long millis) {
- IBinder b = ServiceManager.getService(Context.ALARM_SERVICE);
- IAlarmManager mgr = IAlarmManager.Stub.asInterface(b);
+ final IAlarmManager mgr = IAlarmManager.Stub
+ .asInterface(ServiceManager.getService(Context.ALARM_SERVICE));
if (mgr == null) {
return false;
}
@@ -174,27 +173,25 @@ public final class SystemClock {
native public static long uptimeMillis();
/**
+ * @removed
+ */
+ @Deprecated
+ public static @NonNull Clock uptimeMillisClock() {
+ return uptimeClock();
+ }
+
+ /**
* Return {@link Clock} that starts at system boot, not counting time spent
* in deep sleep.
+ *
+ * @removed
*/
- public static @NonNull Clock uptimeMillisClock() {
- return new Clock() {
- @Override
- public ZoneId getZone() {
- return ZoneOffset.UTC;
- }
- @Override
- public Clock withZone(ZoneId zone) {
- throw new UnsupportedOperationException();
- }
+ public static @NonNull Clock uptimeClock() {
+ return new SimpleClock(ZoneOffset.UTC) {
@Override
public long millis() {
return SystemClock.uptimeMillis();
}
- @Override
- public Instant instant() {
- return Instant.ofEpochMilli(millis());
- }
};
}
@@ -209,25 +206,15 @@ public final class SystemClock {
/**
* Return {@link Clock} that starts at system boot, including time spent in
* sleep.
+ *
+ * @removed
*/
public static @NonNull Clock elapsedRealtimeClock() {
- return new Clock() {
- @Override
- public ZoneId getZone() {
- return ZoneOffset.UTC;
- }
- @Override
- public Clock withZone(ZoneId zone) {
- throw new UnsupportedOperationException();
- }
+ return new SimpleClock(ZoneOffset.UTC) {
@Override
public long millis() {
return SystemClock.elapsedRealtime();
}
- @Override
- public Instant instant() {
- return Instant.ofEpochMilli(millis());
- }
};
}
@@ -266,4 +253,62 @@ public final class SystemClock {
*/
@CriticalNative
public static native long currentTimeMicro();
+
+ /**
+ * Returns milliseconds since January 1, 1970 00:00:00.0 UTC, synchronized
+ * using a remote network source outside the device.
+ * <p>
+ * While the time returned by {@link System#currentTimeMillis()} can be
+ * adjusted by the user, the time returned by this method cannot be adjusted
+ * by the user. Note that synchronization may occur using an insecure
+ * network protocol, so the returned time should not be used for security
+ * purposes.
+ * <p>
+ * This performs no blocking network operations and returns values based on
+ * a recent successful synchronization event; it will either return a valid
+ * time or throw.
+ *
+ * @throws DateTimeException when no accurate network time can be provided.
+ */
+ public static long currentNetworkTimeMillis() {
+ final IAlarmManager mgr = IAlarmManager.Stub
+ .asInterface(ServiceManager.getService(Context.ALARM_SERVICE));
+ if (mgr != null) {
+ try {
+ return mgr.currentNetworkTimeMillis();
+ } catch (ParcelableException e) {
+ e.maybeRethrow(DateTimeException.class);
+ throw new RuntimeException(e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ throw new RuntimeException(new DeadSystemException());
+ }
+ }
+
+ /**
+ * Returns a {@link Clock} that starts at January 1, 1970 00:00:00.0 UTC,
+ * synchronized using a remote network source outside the device.
+ * <p>
+ * While the time returned by {@link System#currentTimeMillis()} can be
+ * adjusted by the user, the time returned by this method cannot be adjusted
+ * by the user. Note that synchronization may occur using an insecure
+ * network protocol, so the returned time should not be used for security
+ * purposes.
+ * <p>
+ * This performs no blocking network operations and returns values based on
+ * a recent successful synchronization event; it will either return a valid
+ * time or throw.
+ *
+ * @throws DateTimeException when no accurate network time can be provided.
+ */
+ public static @NonNull Clock currentNetworkTimeClock() {
+ return new SimpleClock(ZoneOffset.UTC) {
+ @Override
+ public long millis() {
+ return SystemClock.currentNetworkTimeMillis();
+ }
+ };
+ }
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 7e7af1a12299..185620066454 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1678,6 +1678,18 @@ public class UserManager {
}
/**
+ * @hide
+ * Returns whether any user on the device has the given user restriction set.
+ */
+ public boolean hasUserRestrictionOnAnyUser(String restrictionKey) {
+ try {
+ return mService.hasUserRestrictionOnAnyUser(restrictionKey);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Return the serial number for a user. This is a device-unique
* number assigned to that user; if the user is deleted and then a new
* user created, the new users will not be given the same serial number.
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 4a976403e7a8..57418c8b9879 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -33,6 +33,7 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.UUID;
/*package*/ class ZygoteStartFailedEx extends Exception {
ZygoteStartFailedEx(String s) {
@@ -217,7 +218,8 @@ public class ZygoteProcess {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
- abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
+ abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
+ zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
@@ -333,6 +335,8 @@ public class ZygoteProcess {
* @param abi the ABI the process should use.
* @param instructionSet null-ok the instruction set to use.
* @param appDataDir null-ok the data directory of the app.
+ * @param startChildZygote Start a sub-zygote. This creates a new zygote process
+ * that has its state cloned from this zygote process.
* @param extraArgs Additional arguments to supply to the zygote process.
* @return An object that describes the result of the attempt to start the process.
* @throws ZygoteStartFailedEx if process start failed for any reason
@@ -348,6 +352,7 @@ public class ZygoteProcess {
String instructionSet,
String appDataDir,
String invokeWith,
+ boolean startChildZygote,
String[] extraArgs)
throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<String>();
@@ -404,6 +409,10 @@ public class ZygoteProcess {
argsForZygote.add(invokeWith);
}
+ if (startChildZygote) {
+ argsForZygote.add("--start-child-zygote");
+ }
+
argsForZygote.add(processClass);
if (extraArgs != null) {
@@ -418,6 +427,18 @@ public class ZygoteProcess {
}
/**
+ * Closes the connections to the zygote, if they exist.
+ */
+ public void close() {
+ if (primaryZygoteState != null) {
+ primaryZygoteState.close();
+ }
+ if (secondaryZygoteState != null) {
+ secondaryZygoteState.close();
+ }
+ }
+
+ /**
* Tries to establish a connection to the zygote that handles a given {@code abi}. Might block
* and retry if the zygote is unresponsive. This method is a no-op if a connection is
* already open.
@@ -549,4 +570,36 @@ public class ZygoteProcess {
}
Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket " + address.getName());
}
+
+ /**
+ * Starts a new zygote process as a child of this zygote. This is used to create
+ * secondary zygotes that inherit data from the zygote that this object
+ * communicates with. This returns a new ZygoteProcess representing a connection
+ * to the newly created zygote. Throws an exception if the zygote cannot be started.
+ */
+ public ChildZygoteProcess startChildZygote(final String processClass,
+ final String niceName,
+ int uid, int gid, int[] gids,
+ int runtimeFlags,
+ String seInfo,
+ String abi,
+ String instructionSet) {
+ // Create an unguessable address in the global abstract namespace.
+ final LocalSocketAddress serverAddress = new LocalSocketAddress(
+ processClass + "/" + UUID.randomUUID().toString());
+
+ final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName()};
+
+ Process.ProcessStartResult result;
+ try {
+ result = startViaZygote(processClass, niceName, uid, gid,
+ gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
+ abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
+ true /* startChildZygote */, extraArgs);
+ } catch (ZygoteStartFailedEx ex) {
+ throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
+ }
+
+ return new ChildZygoteProcess(serverAddress, result.pid);
+ }
}
diff --git a/core/java/android/os/storage/StorageResultCode.java b/core/java/android/os/storage/StorageResultCode.java
deleted file mode 100644
index c8438870585a..000000000000
--- a/core/java/android/os/storage/StorageResultCode.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 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
- *
- * 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.storage;
-
-/**
- * Class that provides access to constants returned from StorageManager
- * and lower level StorageManagerService APIs.
- *
- * @hide
- */
-public class StorageResultCode
-{
- /**
- * Operation succeeded.
- * @see android.os.storage.StorageManager
- */
- public static final int OperationSucceeded = 0;
-
- /**
- * Operation failed: Internal error.
- * @see android.os.storage.StorageManager
- */
- public static final int OperationFailedInternalError = -1;
-
- /**
- * Operation failed: Missing media.
- * @see android.os.storage.StorageManager
- */
- public static final int OperationFailedNoMedia = -2;
-
- /**
- * Operation failed: Media is blank.
- * @see android.os.storage.StorageManager
- */
- public static final int OperationFailedMediaBlank = -3;
-
- /**
- * Operation failed: Media is corrupt.
- * @see android.os.storage.StorageManager
- */
- public static final int OperationFailedMediaCorrupt = -4;
-
- /**
- * Operation failed: Storage not mounted.
- * @see android.os.storage.StorageManager
- */
- public static final int OperationFailedStorageNotMounted = -5;
-
- /**
- * Operation failed: Storage is mounted.
- * @see android.os.storage.StorageManager
- */
- public static final int OperationFailedStorageMounted = -6;
-
- /**
- * Operation failed: Storage is busy.
- * @see android.os.storage.StorageManager
- */
- public static final int OperationFailedStorageBusy = -7;
-
-}
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 51b77980fcf4..e436bc6ea30f 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -18,6 +18,7 @@ package android.print;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -27,6 +28,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
+import android.content.pm.PackageManager;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -104,6 +106,7 @@ import java.util.Map;
* @see PrintJobInfo
*/
@SystemService(Context.PRINT_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_PRINTING)
public final class PrintManager {
private static final String LOG_TAG = "PrintManager";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 021c22c763af..26c3732f29a5 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3692,18 +3692,15 @@ public final class Settings {
new SettingsValidators.InclusiveIntegerRangeValidator(0, 3);
/**
- * User-selected RTT mode
+ * User-selected RTT mode. When on, outgoing and incoming calls will be answered as RTT
+ * calls when supported by the device and carrier. Boolean value.
* 0 = OFF
- * 1 = FULL
- * 2 = VCO
- * 3 = HCO
- * Uses the same constants as TTY (e.g. {@link android.telecom.TelecomManager#TTY_MODE_OFF})
- * @hide
+ * 1 = ON
*/
public static final String RTT_CALLING_MODE = "rtt_calling_mode";
/** @hide */
- public static final Validator RTT_CALLING_MODE_VALIDATOR = TTY_MODE_VALIDATOR;
+ public static final Validator RTT_CALLING_MODE_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Whether the sounds effects (key clicks, lid open ...) are enabled. The value is
@@ -5385,6 +5382,17 @@ public final class Settings {
"autofill_user_data_max_field_classification_size";
/**
+ * Defines value returned by
+ * {@link android.service.autofill.UserData#getMaxCategoryCount()}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final String AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT =
+ "autofill_user_data_max_category_count";
+
+ /**
* Defines value returned by {@link android.service.autofill.UserData#getMaxValueLength()}.
*
* @hide
@@ -5443,32 +5451,6 @@ public final class Settings {
*/
public static final String ENABLED_INPUT_METHODS = "enabled_input_methods";
- private static final Validator ENABLED_INPUT_METHODS_VALIDATOR = new Validator() {
- @Override
- public boolean validate(String value) {
- if (value == null) {
- return false;
- }
- String[] inputMethods = value.split(":");
- boolean valid = true;
- for (String inputMethod : inputMethods) {
- if (inputMethod.length() == 0) {
- return false;
- }
- String[] subparts = inputMethod.split(";");
- for (String subpart : subparts) {
- // allow either a non negative integer or a ComponentName
- valid |= (NON_NEGATIVE_INTEGER_VALIDATOR.validate(subpart)
- || COMPONENT_NAME_VALIDATOR.validate(subpart));
- }
- if (!valid) {
- return false;
- }
- }
- return valid;
- }
- };
-
/**
* List of system input methods that are currently disabled. This is a string
* containing the IDs of all disabled input methods, each ID separated
@@ -7709,7 +7691,6 @@ public final class Settings {
ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
ENABLED_ACCESSIBILITY_SERVICES,
ENABLED_VR_LISTENERS,
- ENABLED_INPUT_METHODS,
TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
TOUCH_EXPLORATION_ENABLED,
ACCESSIBILITY_ENABLED,
@@ -7815,7 +7796,6 @@ public final class Settings {
VALIDATORS.put(ENABLED_ACCESSIBILITY_SERVICES,
ENABLED_ACCESSIBILITY_SERVICES_VALIDATOR);
VALIDATORS.put(ENABLED_VR_LISTENERS, ENABLED_VR_LISTENERS_VALIDATOR);
- VALIDATORS.put(ENABLED_INPUT_METHODS, ENABLED_INPUT_METHODS_VALIDATOR);
VALIDATORS.put(TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES_VALIDATOR);
VALIDATORS.put(TOUCH_EXPLORATION_ENABLED, TOUCH_EXPLORATION_ENABLED_VALIDATOR);
@@ -8780,6 +8760,7 @@ public final class Settings {
/** {@hide} */
public static final String NETSTATS_POLL_INTERVAL = "netstats_poll_interval";
/** {@hide} */
+ @Deprecated
public static final String NETSTATS_TIME_CACHE_MAX_AGE = "netstats_time_cache_max_age";
/** {@hide} */
public static final String NETSTATS_GLOBAL_ALERT_BYTES = "netstats_global_alert_bytes";
@@ -10477,6 +10458,9 @@ public final class Settings {
* <pre>
* smart_selection_dark_launch (boolean)
* smart_selection_enabled_for_edit_text (boolean)
+ * suggest_selection_max_range_length (int)
+ * classify_text_max_range_length (int)
+ * generate_links_max_text_length (int)
* </pre>
*
* <p>
@@ -10495,6 +10479,7 @@ public final class Settings {
* track_cpu_times_by_proc_state (boolean)
* track_cpu_active_cluster_time (boolean)
* read_binary_cpu_time (boolean)
+ * proc_state_cpu_times_read_delay_ms (long)
* </pre>
*
* <p>
@@ -10505,6 +10490,16 @@ public final class Settings {
public static final String BATTERY_STATS_CONSTANTS = "battery_stats_constants";
/**
+ * SyncManager specific settings.
+ *
+ * <p>
+ * Type: string
+ * @hide
+ * @see com.android.server.content.SyncManagerConstants
+ */
+ public static final String SYNC_MANAGER_CONSTANTS = "sync_manager_constants";
+
+ /**
* Whether or not App Standby feature is enabled. This controls throttling of apps
* based on usage patterns and predictions.
* Type: int (0 for false, 1 for true)
@@ -11372,7 +11367,8 @@ public final class Settings {
"chained_battery_attribution_enabled";
/**
- * The packages whitelisted to be run in autofill compatibility mode.
+ * The packages whitelisted to be run in autofill compatibility mode. The list
+ * of packages is ":" colon delimited.
*
* @hide
*/
@@ -11381,6 +11377,14 @@ public final class Settings {
"autofill_compat_allowed_packages";
/**
+ * Exemptions to the hidden API blacklist.
+ *
+ * @hide
+ */
+ public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS =
+ "hidden_api_blacklist_exemptions";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
@@ -12079,6 +12083,28 @@ public final class Settings {
"enable_gnss_raw_meas_full_tracking";
/**
+ * Whether the notification should be ongoing (persistent) when a carrier app install is
+ * required.
+ *
+ * The value is a boolean (1 or 0).
+ * @hide
+ */
+ @SystemApi
+ public static final String INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT =
+ "install_carrier_app_notification_persistent";
+
+ /**
+ * The amount of time (ms) to hide the install carrier app notification after the user has
+ * ignored it. After this time passes, the notification will be shown again
+ *
+ * The value is a long
+ * @hide
+ */
+ @SystemApi
+ public static final String INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS =
+ "install_carrier_app_notification_sleep_millis";
+
+ /**
* Whether we've enabled zram on this device. Takes effect on
* reboot. The value "1" enables zram; "0" disables it, and
* everything else is unspecified.
@@ -12124,6 +12150,12 @@ public final class Settings {
* @hide
*/
public static final String SHOW_MUTE_IN_CRASH_DIALOG = "show_mute_in_crash_dialog";
+
+ /**
+ * If nonzero, will show the zen upgrade notification when the user toggles DND on/off.
+ * @hide
+ */
+ public static final String SHOW_ZEN_UPGRADE_NOTIFICATION = "show_zen_upgrade_notification";
}
/**
diff --git a/core/java/android/provider/SettingsSlicesContract.java b/core/java/android/provider/SettingsSlicesContract.java
index f79d852ddefc..7dc948899dfe 100644
--- a/core/java/android/provider/SettingsSlicesContract.java
+++ b/core/java/android/provider/SettingsSlicesContract.java
@@ -31,12 +31,12 @@ import android.net.Uri;
* <p>
* {@link Uri} builder example:
* <pre>
- * Uri wifiActionUri = AUTHORITY_URI
+ * Uri wifiActionUri = BASE_URI
* .buildUpon()
* .appendPath(PATH_SETTING_ACTION)
* .appendPath(KEY_WIFI)
* .build();
- * Uri bluetoothIntentUri = AUTHORITY_URI
+ * Uri bluetoothIntentUri = BASE_URI
* .buildUpon()
* .appendPath(PATH_SETTING_INTENT)
* .appendPath(KEY_BLUETOOTH)
diff --git a/core/java/android/security/IConfirmationPromptCallback.aidl b/core/java/android/security/IConfirmationPromptCallback.aidl
deleted file mode 100644
index 96a1a04828b5..000000000000
--- a/core/java/android/security/IConfirmationPromptCallback.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security;
-
-/**
- * This must be kept manually in sync with system/security/keystore until AIDL
- * can generate both Java and C++ bindings.
- *
- * @hide
- */
-interface IConfirmationPromptCallback {
- oneway void onConfirmationPromptCompleted(in int result, in byte[] dataThatWasConfirmed);
-}
diff --git a/core/java/android/security/IKeystoreService.aidl b/core/java/android/security/IKeystoreService.aidl
deleted file mode 100644
index 738eb6865230..000000000000
--- a/core/java/android/security/IKeystoreService.aidl
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security;
-
-import android.security.keymaster.ExportResult;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterCertificateChain;
-import android.security.keymaster.KeymasterBlob;
-import android.security.keymaster.OperationResult;
-import android.security.KeystoreArguments;
-
-/**
- * This must be kept manually in sync with system/security/keystore until AIDL
- * can generate both Java and C++ bindings.
- *
- * @hide
- */
-interface IKeystoreService {
- int getState(int userId);
- byte[] get(String name, int uid);
- int insert(String name, in byte[] item, int uid, int flags);
- int del(String name, int uid);
- int exist(String name, int uid);
- String[] list(String namePrefix, int uid);
- int reset();
- int onUserPasswordChanged(int userId, String newPassword);
- int lock(int userId);
- int unlock(int userId, String userPassword);
- int isEmpty(int userId);
- int generate(String name, int uid, int keyType, int keySize, int flags,
- in KeystoreArguments args);
- int import_key(String name, in byte[] data, int uid, int flags);
- byte[] sign(String name, in byte[] data);
- int verify(String name, in byte[] data, in byte[] signature);
- byte[] get_pubkey(String name);
- String grant(String name, int granteeUid);
- int ungrant(String name, int granteeUid);
- long getmtime(String name, int uid);
- int is_hardware_backed(String string);
- int clear_uid(long uid);
-
- // Keymaster 0.4 methods
- int addRngEntropy(in byte[] data, int flags);
- int generateKey(String alias, in KeymasterArguments arguments, in byte[] entropy, int uid,
- int flags, out KeyCharacteristics characteristics);
- int getKeyCharacteristics(String alias, in KeymasterBlob clientId, in KeymasterBlob appId,
- int uid, out KeyCharacteristics characteristics);
- int importKey(String alias, in KeymasterArguments arguments, int format,
- in byte[] keyData, int uid, int flags, out KeyCharacteristics characteristics);
- ExportResult exportKey(String alias, int format, in KeymasterBlob clientId,
- in KeymasterBlob appId, int uid);
- OperationResult begin(IBinder appToken, String alias, int purpose, boolean pruneable,
- in KeymasterArguments params, in byte[] entropy, int uid);
- OperationResult update(IBinder token, in KeymasterArguments params, in byte[] input);
- OperationResult finish(IBinder token, in KeymasterArguments params, in byte[] signature,
- in byte[] entropy);
- int abort(IBinder handle);
- boolean isOperationAuthorized(IBinder token);
- int addAuthToken(in byte[] authToken);
- int onUserAdded(int userId, int parentId);
- int onUserRemoved(int userId);
- int attestKey(String alias, in KeymasterArguments params, out KeymasterCertificateChain chain);
- int attestDeviceIds(in KeymasterArguments params, out KeymasterCertificateChain chain);
- int onDeviceOffBody();
- int importWrappedKey(in String wrappedKeyAlias, in byte[] wrappedKey,
- in String wrappingKeyAlias, in byte[] maskingKey, in KeymasterArguments arguments,
- in long rootSid, in long fingerprintSid,
- out KeyCharacteristics characteristics);
- int presentConfirmationPrompt(IBinder listener, String promptText, in byte[] extraData,
- in String locale, in int uiOptionsAsFlags);
- int cancelConfirmationPrompt(IBinder listener);
-}
diff --git a/core/java/android/security/KeystoreArguments.aidl b/core/java/android/security/KeystoreArguments.aidl
deleted file mode 100644
index dc8ed50182ed..000000000000
--- a/core/java/android/security/KeystoreArguments.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security;
-
-/* @hide */
-parcelable KeystoreArguments cpp_header "keystore/KeystoreArguments.h";
diff --git a/core/java/android/security/keymaster/KeymasterArguments.aidl b/core/java/android/security/keymaster/KeymasterArguments.aidl
deleted file mode 100644
index 44d9f0954781..000000000000
--- a/core/java/android/security/keymaster/KeymasterArguments.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keymaster;
-
-/* @hide */
-parcelable KeymasterArguments cpp_header "keystore/KeymasterArguments.h";
diff --git a/core/java/android/security/keymaster/KeymasterBlob.aidl b/core/java/android/security/keymaster/KeymasterBlob.aidl
deleted file mode 100644
index 5c5db9ec314b..000000000000
--- a/core/java/android/security/keymaster/KeymasterBlob.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keymaster;
-
-/* @hide */
-parcelable KeymasterBlob cpp_header "keystore/KeymasterBlob.h";
diff --git a/core/java/android/security/keymaster/KeymasterCertificateChain.aidl b/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
deleted file mode 100644
index ddb5cae1a254..000000000000
--- a/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keymaster;
-
-/* @hide */
-parcelable KeymasterCertificateChain cpp_header "keystore/KeymasterCertificateChain.h";
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index 1d1333504350..f4dcce1e7e58 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -75,6 +75,7 @@ public final class KeymasterDefs {
public static final int KM_TAG_ALLOW_WHILE_ON_BODY = KM_BOOL | 506;
public static final int KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED = KM_BOOL | 507;
public static final int KM_TAG_TRUSTED_CONFIRMATION_REQUIRED = KM_BOOL | 508;
+ public static final int KM_TAG_UNLOCKED_DEVICE_REQUIRED = KM_BOOL | 509;
public static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600;
public static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601;
@@ -216,6 +217,7 @@ public final class KeymasterDefs {
public static final int KM_ERROR_MISSING_MIN_MAC_LENGTH = -58;
public static final int KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH = -59;
public static final int KM_ERROR_CANNOT_ATTEST_IDS = -66;
+ public static final int KM_ERROR_DEVICE_LOCKED = -72;
public static final int KM_ERROR_UNIMPLEMENTED = -100;
public static final int KM_ERROR_VERSION_MISMATCH = -101;
public static final int KM_ERROR_UNKNOWN_ERROR = -1000;
@@ -262,6 +264,7 @@ public final class KeymasterDefs {
sErrorCodeToString.put(KM_ERROR_INVALID_MAC_LENGTH,
"Invalid MAC or authentication tag length");
sErrorCodeToString.put(KM_ERROR_CANNOT_ATTEST_IDS, "Unable to attest device ids");
+ sErrorCodeToString.put(KM_ERROR_DEVICE_LOCKED, "Device locked");
sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented");
sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error");
}
diff --git a/core/java/android/security/keymaster/OperationResult.aidl b/core/java/android/security/keymaster/OperationResult.aidl
deleted file mode 100644
index db689d46521a..000000000000
--- a/core/java/android/security/keymaster/OperationResult.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keymaster;
-
-/* @hide */
-parcelable OperationResult cpp_header "keystore/OperationResult.h";
diff --git a/core/java/android/security/keystore/OWNERS b/core/java/android/security/keystore/OWNERS
new file mode 100644
index 000000000000..bb487fb52c9f
--- /dev/null
+++ b/core/java/android/security/keystore/OWNERS
@@ -0,0 +1,4 @@
+aseemk@google.com
+bozhu@google.com
+dementyev@google.com
+robertberry@google.com
diff --git a/core/java/android/service/autofill/AutofillServiceInfo.java b/core/java/android/service/autofill/AutofillServiceInfo.java
index 7383de738ad6..70c4ec07ee4e 100644
--- a/core/java/android/service/autofill/AutofillServiceInfo.java
+++ b/core/java/android/service/autofill/AutofillServiceInfo.java
@@ -32,12 +32,12 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Pair;
import android.util.Xml;
import com.android.internal.R;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -45,7 +45,6 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.io.PrintWriter;
-import java.util.Map;
/**
* {@link ServiceInfo} and meta-data about an {@link AutofillService}.
@@ -80,7 +79,7 @@ public final class AutofillServiceInfo {
private final String mSettingsActivity;
@Nullable
- private final Map<String, Long> mCompatibilityPackages;
+ private final ArrayMap<String, Pair<Long, String>> mCompatibilityPackages;
public AutofillServiceInfo(Context context, ComponentName comp, int userHandle)
throws PackageManager.NameNotFoundException {
@@ -118,7 +117,7 @@ public final class AutofillServiceInfo {
}
String settingsActivity = null;
- Map<String, Long> compatibilityPackages = null;
+ ArrayMap<String, Pair<Long, String>> compatibilityPackages = null;
try {
final Resources resources = context.getPackageManager().getResourcesForApplication(
@@ -154,9 +153,10 @@ public final class AutofillServiceInfo {
mCompatibilityPackages = compatibilityPackages;
}
- private Map<String, Long> parseCompatibilityPackages(XmlPullParser parser, Resources resources)
+ private ArrayMap<String, Pair<Long, String>> parseCompatibilityPackages(XmlPullParser parser,
+ Resources resources)
throws IOException, XmlPullParserException {
- Map<String, Long> compatibilityPackages = null;
+ ArrayMap<String, Pair<Long, String>> compatibilityPackages = null;
final int outerDepth = parser.getDepth();
int type;
@@ -200,11 +200,13 @@ public final class AutofillServiceInfo {
} else {
maxVersionCode = Long.MAX_VALUE;
}
+ final String urlBarResourceId = cpAttributes.getString(
+ R.styleable.AutofillService_CompatibilityPackage_urlBarResourceId);
if (compatibilityPackages == null) {
compatibilityPackages = new ArrayMap<>();
}
- compatibilityPackages.put(name, maxVersionCode);
+ compatibilityPackages.put(name, new Pair<>(maxVersionCode, urlBarResourceId));
} finally {
XmlUtils.skipCurrentTag(parser);
if (cpAttributes != null) {
@@ -226,16 +228,21 @@ public final class AutofillServiceInfo {
return mSettingsActivity;
}
+ public ArrayMap<String, Pair<Long, String>> getCompatibilityPackages() {
+ return mCompatibilityPackages;
+ }
+
+ /**
+ * Gets the resource id of the URL bar for a package. Used in compat mode
+ */
+ // TODO: return a list of strings instead
@Nullable
- public boolean isCompatibilityModeRequested(String packageName, long versionCode) {
+ public String getUrlBarResourceId(String packageName) {
if (mCompatibilityPackages == null) {
- return false;
- }
- final Long maxVersionCode = mCompatibilityPackages.get(packageName);
- if (maxVersionCode == null) {
- return false;
+ return null;
}
- return versionCode <= maxVersionCode;
+ final Pair<Long, String> pair = mCompatibilityPackages.get(packageName);
+ return pair == null ? null : pair.second;
}
@Override
diff --git a/core/java/android/service/autofill/DateTransformation.java b/core/java/android/service/autofill/DateTransformation.java
index 4e1425d86380..ec24a09a470f 100644
--- a/core/java/android/service/autofill/DateTransformation.java
+++ b/core/java/android/service/autofill/DateTransformation.java
@@ -20,6 +20,7 @@ import static android.view.autofill.Helper.sDebug;
import android.annotation.NonNull;
import android.annotation.TestApi;
+import android.icu.text.DateFormat;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -30,7 +31,6 @@ import android.widget.TextView;
import com.android.internal.util.Preconditions;
-import java.text.DateFormat;
import java.util.Date;
/**
diff --git a/core/java/android/service/autofill/DateValueSanitizer.java b/core/java/android/service/autofill/DateValueSanitizer.java
index 0f7b540f8a24..4f797f46da2a 100644
--- a/core/java/android/service/autofill/DateValueSanitizer.java
+++ b/core/java/android/service/autofill/DateValueSanitizer.java
@@ -21,6 +21,7 @@ import static android.view.autofill.Helper.sDebug;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
+import android.icu.text.DateFormat;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -28,7 +29,6 @@ import android.view.autofill.AutofillValue;
import com.android.internal.util.Preconditions;
-import java.text.DateFormat;
import java.util.Date;
/**
diff --git a/core/java/android/service/autofill/FieldClassification.java b/core/java/android/service/autofill/FieldClassification.java
index cd1efd68df6f..5bf56cb9c1b5 100644
--- a/core/java/android/service/autofill/FieldClassification.java
+++ b/core/java/android/service/autofill/FieldClassification.java
@@ -108,21 +108,21 @@ public final class FieldClassification {
*/
public static final class Match {
- private final String mRemoteId;
+ private final String mCategoryId;
private final float mScore;
/** @hide */
- public Match(String remoteId, float score) {
- mRemoteId = Preconditions.checkNotNull(remoteId);
+ public Match(String categoryId, float score) {
+ mCategoryId = Preconditions.checkNotNull(categoryId);
mScore = score;
}
/**
- * Gets the remote id of the {@link UserData} entry.
+ * Gets the category id of the {@link UserData} entry.
*/
@NonNull
- public String getRemoteId() {
- return mRemoteId;
+ public String getCategoryId() {
+ return mCategoryId;
}
/**
@@ -149,13 +149,13 @@ public final class FieldClassification {
public String toString() {
if (!sDebug) return super.toString();
- final StringBuilder string = new StringBuilder("Match: remoteId=");
- Helper.appendRedacted(string, mRemoteId);
+ final StringBuilder string = new StringBuilder("Match: categoryId=");
+ Helper.appendRedacted(string, mCategoryId);
return string.append(", score=").append(mScore).toString();
}
private void writeToParcel(@NonNull Parcel parcel) {
- parcel.writeString(mRemoteId);
+ parcel.writeString(mCategoryId);
parcel.writeFloat(mScore);
}
diff --git a/core/java/android/service/autofill/FillContext.java b/core/java/android/service/autofill/FillContext.java
index cda2f4a23c9a..535c00bc5319 100644
--- a/core/java/android/service/autofill/FillContext.java
+++ b/core/java/android/service/autofill/FillContext.java
@@ -177,30 +177,6 @@ public final class FillContext implements Parcelable {
return foundNodes;
}
- /**
- * Finds the {@link ViewNode} that has the requested {@code id}, if any.
- *
- * @hide
- */
- @Nullable public ViewNode findViewNodeByAutofillId(@NonNull AutofillId id) {
- final LinkedList<ViewNode> nodesToProcess = new LinkedList<>();
- final int numWindowNodes = mStructure.getWindowNodeCount();
- for (int i = 0; i < numWindowNodes; i++) {
- nodesToProcess.add(mStructure.getWindowNodeAt(i).getRootViewNode());
- }
- while (!nodesToProcess.isEmpty()) {
- final ViewNode node = nodesToProcess.removeFirst();
- if (id.equals(node.getAutofillId())) {
- return node;
- }
- for (int i = 0; i < node.getChildCount(); i++) {
- nodesToProcess.addLast(node.getChildAt(i));
- }
- }
-
- return null;
- }
-
public static final Parcelable.Creator<FillContext> CREATOR =
new Parcelable.Creator<FillContext>() {
@Override
diff --git a/core/java/android/service/autofill/UserData.java b/core/java/android/service/autofill/UserData.java
index 6bab6aa82375..a1dd1f846515 100644
--- a/core/java/android/service/autofill/UserData.java
+++ b/core/java/android/service/autofill/UserData.java
@@ -15,6 +15,7 @@
*/
package android.service.autofill;
+import static android.provider.Settings.Secure.AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT;
import static android.provider.Settings.Secure.AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE;
import static android.provider.Settings.Secure.AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE;
import static android.provider.Settings.Secure.AUTOFILL_USER_DATA_MAX_VALUE_LENGTH;
@@ -31,6 +32,7 @@ import android.os.Parcelable;
import android.provider.Settings;
import android.service.autofill.FieldClassification.Match;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.Log;
import android.view.autofill.AutofillManager;
import android.view.autofill.Helper;
@@ -48,23 +50,24 @@ public final class UserData implements Parcelable {
private static final String TAG = "UserData";
- private static final int DEFAULT_MAX_USER_DATA_SIZE = 10;
+ private static final int DEFAULT_MAX_USER_DATA_SIZE = 50;
+ private static final int DEFAULT_MAX_CATEGORY_COUNT = 10;
private static final int DEFAULT_MAX_FIELD_CLASSIFICATION_IDS_SIZE = 10;
- private static final int DEFAULT_MIN_VALUE_LENGTH = 5;
+ private static final int DEFAULT_MIN_VALUE_LENGTH = 3;
private static final int DEFAULT_MAX_VALUE_LENGTH = 100;
private final String mId;
private final String mAlgorithm;
private final Bundle mAlgorithmArgs;
- private final String[] mRemoteIds;
+ private final String[] mCategoryIds;
private final String[] mValues;
private UserData(Builder builder) {
mId = builder.mId;
mAlgorithm = builder.mAlgorithm;
mAlgorithmArgs = builder.mAlgorithmArgs;
- mRemoteIds = new String[builder.mRemoteIds.size()];
- builder.mRemoteIds.toArray(mRemoteIds);
+ mCategoryIds = new String[builder.mCategoryIds.size()];
+ builder.mCategoryIds.toArray(mCategoryIds);
mValues = new String[builder.mValues.size()];
builder.mValues.toArray(mValues);
}
@@ -91,8 +94,8 @@ public final class UserData implements Parcelable {
}
/** @hide */
- public String[] getRemoteIds() {
- return mRemoteIds;
+ public String[] getCategoryIds() {
+ return mCategoryIds;
}
/** @hide */
@@ -106,11 +109,11 @@ public final class UserData implements Parcelable {
pw.print(prefix); pw.print("Algorithm: "); pw.print(mAlgorithm);
pw.print(" Args: "); pw.println(mAlgorithmArgs);
- // Cannot disclose remote ids or values because they could contain PII
- pw.print(prefix); pw.print("Remote ids size: "); pw.println(mRemoteIds.length);
- for (int i = 0; i < mRemoteIds.length; i++) {
+ // Cannot disclose field ids or values because they could contain PII
+ pw.print(prefix); pw.print("Field ids size: "); pw.println(mCategoryIds.length);
+ for (int i = 0; i < mCategoryIds.length; i++) {
pw.print(prefix); pw.print(prefix); pw.print(i); pw.print(": ");
- pw.println(Helper.getRedacted(mRemoteIds[i]));
+ pw.println(Helper.getRedacted(mCategoryIds[i]));
}
pw.print(prefix); pw.print("Values size: "); pw.println(mValues.length);
for (int i = 0; i < mValues.length; i++) {
@@ -124,6 +127,7 @@ public final class UserData implements Parcelable {
pw.print(prefix); pw.print("maxUserDataSize: "); pw.println(getMaxUserDataSize());
pw.print(prefix); pw.print("maxFieldClassificationIdsSize: ");
pw.println(getMaxFieldClassificationIdsSize());
+ pw.print(prefix); pw.print("maxCategoryCount: "); pw.println(getMaxCategoryCount());
pw.print(prefix); pw.print("minValueLength: "); pw.println(getMinValueLength());
pw.print(prefix); pw.print("maxValueLength: "); pw.println(getMaxValueLength());
}
@@ -133,44 +137,59 @@ public final class UserData implements Parcelable {
*/
public static final class Builder {
private final String mId;
- private final ArrayList<String> mRemoteIds;
+ private final ArrayList<String> mCategoryIds;
private final ArrayList<String> mValues;
private String mAlgorithm;
private Bundle mAlgorithmArgs;
private boolean mDestroyed;
+ // Non-persistent array used to limit the number of unique ids.
+ private final ArraySet<String> mUniqueCategoryIds;
+
/**
* Creates a new builder for the user data used for <a href="#FieldClassification">field
* classification</a>.
*
- * <p>The user data must contain at least one pair of {@code remoteId} -> {@code value}, and
- * more pairs can be added through the {@link #add(String, String)} method.
+ * <p>The user data must contain at least one pair of {@code value} -> {@code categoryId},
+ * and more pairs can be added through the {@link #add(String, String)} method. For example:
+ *
+ * <pre class="prettyprint">
+ * new UserData.Builder("v1", "Bart Simpson", "name")
+ * .add("bart.simpson@example.com", "email")
+ * .add("el_barto@example.com", "email")
+ * .build();
+ * </pre>
*
* @param id id used to identify the whole {@link UserData} object. This id is also returned
* by {@link AutofillManager#getUserDataId()}, which can be used to check if the
* {@link UserData} is up-to-date without fetching the whole object (through
* {@link AutofillManager#getUserData()}).
- * @param remoteId unique string used to identify a user data value.
+ *
* @param value value of the user data.
+ * @param categoryId string used to identify the category the value is associated with.
*
* @throws IllegalArgumentException if any of the following occurs:
* <ol>
- * <li>{@code id} is empty
- * <li>{@code remoteId} is empty
- * <li>{@code value} is empty
- * <li>the length of {@code value} is lower than {@link UserData#getMinValueLength()}
- * <li>the length of {@code value} is higher than {@link UserData#getMaxValueLength()}
+ * <li>{@code id} is empty</li>
+ * <li>{@code categoryId} is empty</li>
+ * <li>{@code value} is empty</li>
+ * <li>the length of {@code value} is lower than {@link UserData#getMinValueLength()}</li>
+ * <li>the length of {@code value} is higher than
+ * {@link UserData#getMaxValueLength()}</li>
* </ol>
+ *
*/
- public Builder(@NonNull String id, @NonNull String remoteId, @NonNull String value) {
+ // TODO(b/70407264): ignore entry instead of throwing exception when settings changed
+ public Builder(@NonNull String id, @NonNull String value, @NonNull String categoryId) {
mId = checkNotEmpty("id", id);
- checkNotEmpty("remoteId", remoteId);
+ checkNotEmpty("categoryId", categoryId);
checkValidValue(value);
- final int capacity = getMaxUserDataSize();
- mRemoteIds = new ArrayList<>(capacity);
- mValues = new ArrayList<>(capacity);
- mRemoteIds.add(remoteId);
- mValues.add(value);
+ final int maxUserDataSize = getMaxUserDataSize();
+ mCategoryIds = new ArrayList<>(maxUserDataSize);
+ mValues = new ArrayList<>(maxUserDataSize);
+ mUniqueCategoryIds = new ArraySet<>(getMaxCategoryCount());
+
+ addMapping(value, categoryId);
}
/**
@@ -190,6 +209,7 @@ public final class UserData implements Parcelable {
*/
public Builder setFieldClassificationAlgorithm(@Nullable String name,
@Nullable Bundle args) {
+ throwIfDestroyed();
mAlgorithm = name;
mAlgorithmArgs = args;
return this;
@@ -198,37 +218,58 @@ public final class UserData implements Parcelable {
/**
* Adds a new value for user data.
*
- * @param remoteId unique string used to identify the user data.
* @param value value of the user data.
+ * @param categoryId string used to identify the category the value is associated with.
*
- * @throws IllegalStateException if {@link #build()} or
- * {@link #add(String, String)} with the same {@code remoteId} has already
- * been called, or if the number of values add (i.e., calls made to this method plus
- * constructor) is more than {@link UserData#getMaxUserDataSize()}.
+ * @throws IllegalStateException if:
+ * <ol>
+ * <li>{@link #build()} already called</li>
+ * <li>the {@code value} has already been added</li>
+ * <li>the number of unique {@code categoryId} values added so far is more than
+ * {@link UserData#getMaxCategoryCount()}</li>
+ * <li>the number of {@code values} added so far is is more than
+ * {@link UserData#getMaxUserDataSize()}</li>
+ * </ol>
*
- * @throws IllegalArgumentException if {@code remoteId} or {@code value} are empty or if the
- * length of {@code value} is lower than {@link UserData#getMinValueLength()}
- * or higher than {@link UserData#getMaxValueLength()}.
+ * @throws IllegalArgumentException if any of the following occurs:
+ * <ol>
+ * <li>{@code id} is empty</li>
+ * <li>{@code categoryId} is empty</li>
+ * <li>{@code value} is empty</li>
+ * <li>the length of {@code value} is lower than {@link UserData#getMinValueLength()}</li>
+ * <li>the length of {@code value} is higher than
+ * {@link UserData#getMaxValueLength()}</li>
+ * </ol>
*/
- public Builder add(@NonNull String remoteId, @NonNull String value) {
+ // TODO(b/70407264): ignore entry instead of throwing exception when settings changed
+ public Builder add(@NonNull String value, @NonNull String categoryId) {
throwIfDestroyed();
- checkNotEmpty("remoteId", remoteId);
+ checkNotEmpty("categoryId", categoryId);
checkValidValue(value);
- Preconditions.checkState(!mRemoteIds.contains(remoteId),
- // Don't include remoteId on message because it could contain PII
- "already has entry with same remoteId");
+ if (!mUniqueCategoryIds.contains(categoryId)) {
+ // New category - check size
+ Preconditions.checkState(mUniqueCategoryIds.size() < getMaxCategoryCount(),
+ "already added " + mUniqueCategoryIds.size() + " unique category ids");
+
+ }
+
Preconditions.checkState(!mValues.contains(value),
- // Don't include remoteId on message because it could contain PII
+ // Don't include value on message because it could contain PII
"already has entry with same value");
- Preconditions.checkState(mRemoteIds.size() < getMaxUserDataSize(),
- "already added " + mRemoteIds.size() + " elements");
- mRemoteIds.add(remoteId);
- mValues.add(value);
+ Preconditions.checkState(mValues.size() < getMaxUserDataSize(),
+ "already added " + mValues.size() + " elements");
+ addMapping(value, categoryId);
return this;
}
+ private void addMapping(@NonNull String value, @NonNull String categoryId) {
+ mCategoryIds.add(categoryId);
+ mValues.add(value);
+ mUniqueCategoryIds.add(categoryId);
+ }
+
private String checkNotEmpty(@NonNull String name, @Nullable String value) {
Preconditions.checkNotNull(value);
Preconditions.checkArgument(!TextUtils.isEmpty(value), "%s cannot be empty", name);
@@ -273,9 +314,9 @@ public final class UserData implements Parcelable {
final StringBuilder builder = new StringBuilder("UserData: [id=").append(mId)
.append(", algorithm=").append(mAlgorithm);
- // Cannot disclose remote ids or values because they could contain PII
- builder.append(", remoteIds=");
- Helper.appendRedacted(builder, mRemoteIds);
+ // Cannot disclose category ids or values because they could contain PII
+ builder.append(", categoryIds=");
+ Helper.appendRedacted(builder, mCategoryIds);
builder.append(", values=");
Helper.appendRedacted(builder, mValues);
return builder.append("]").toString();
@@ -293,7 +334,7 @@ public final class UserData implements Parcelable {
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(mId);
- parcel.writeStringArray(mRemoteIds);
+ parcel.writeStringArray(mCategoryIds);
parcel.writeStringArray(mValues);
parcel.writeString(mAlgorithm);
parcel.writeBundle(mAlgorithmArgs);
@@ -307,12 +348,12 @@ public final class UserData implements Parcelable {
// the system obeys the contract of the builder to avoid attacks
// using specially crafted parcels.
final String id = parcel.readString();
- final String[] remoteIds = parcel.readStringArray();
+ final String[] categoryIds = parcel.readStringArray();
final String[] values = parcel.readStringArray();
- final Builder builder = new Builder(id, remoteIds[0], values[0])
+ final Builder builder = new Builder(id, values[0], categoryIds[0])
.setFieldClassificationAlgorithm(parcel.readString(), parcel.readBundle());
- for (int i = 1; i < remoteIds.length; i++) {
- builder.add(remoteIds[i], values[i]);
+ for (int i = 1; i < categoryIds.length; i++) {
+ builder.add(values[i], categoryIds[i]);
}
return builder.build();
}
@@ -340,6 +381,14 @@ public final class UserData implements Parcelable {
}
/**
+ * Gets the maximum number of unique category ids that can be passed to
+ * the builder's constructor and {@link Builder#add(String, String)}.
+ */
+ public static int getMaxCategoryCount() {
+ return getInt(AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT, DEFAULT_MAX_CATEGORY_COUNT);
+ }
+
+ /**
* Gets the minimum length of values passed to the builder's constructor or
* or {@link Builder#add(String, String)}.
*/
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index d66322c3aa89..171d4d938beb 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -94,7 +94,7 @@ public class ZenModeConfig implements Parcelable {
private static final boolean DEFAULT_ALLOW_SCREEN_OFF = true;
private static final boolean DEFAULT_ALLOW_SCREEN_ON = true;
- private static final int XML_VERSION = 2;
+ public static final int XML_VERSION = 3;
public static final String ZEN_TAG = "zen";
private static final String ZEN_ATT_VERSION = "version";
private static final String ZEN_ATT_USER = "user";
@@ -145,6 +145,7 @@ public class ZenModeConfig implements Parcelable {
public int user = UserHandle.USER_SYSTEM;
public boolean allowWhenScreenOff = DEFAULT_ALLOW_SCREEN_OFF;
public boolean allowWhenScreenOn = DEFAULT_ALLOW_SCREEN_ON;
+ public int version;
public ZenRule manualRule;
public ArrayMap<String, ZenRule> automaticRules = new ArrayMap<>();
@@ -431,6 +432,7 @@ public class ZenModeConfig implements Parcelable {
String tag = parser.getName();
if (!ZEN_TAG.equals(tag)) return null;
final ZenModeConfig rt = new ZenModeConfig();
+ rt.version = safeInt(parser, ZEN_ATT_VERSION, XML_VERSION);
rt.user = safeInt(parser, ZEN_ATT_USER, rt.user);
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
tag = parser.getName();
diff --git a/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java b/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java
index 704a1daf3ec7..2ed618b39f1f 100644
--- a/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java
+++ b/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java
@@ -15,17 +15,17 @@
*/
package android.speech.tts;
+import android.media.AudioTrack;
import android.speech.tts.TextToSpeechService.AudioOutputParams;
import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
-import android.media.AudioTrack;
import android.util.Log;
import java.util.LinkedList;
+import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
-import java.util.concurrent.ConcurrentLinkedQueue;
/**
* Manages the playback of a list of byte arrays representing audio data that are queued by the
@@ -157,9 +157,16 @@ final class SynthesisPlaybackQueueItem extends PlaybackQueueItem
mStopped = true;
mStatusCode = statusCode;
+ // Wake up the synthesis thread if it was waiting on put(). Its
+ // buffers will no longer be copied since mStopped is true. The
+ // PlaybackSynthesisCallback that this synthesis corresponds to
+ // would also have been stopped, and so all calls to
+ // Callback.onDataAvailable( ) will return errors too.
+ mNotFull.signal();
+
if (mRunState.getAndSet(STOP_CALLED) == NOT_RUN) {
- // Dispatch the status code and just finish without signaling
- // if run() has not even started.
+ // Dispatch the status code and just finish. Signaling audio
+ // playback is not necessary because run() hasn't started.
dispatchEndStatus();
return;
}
@@ -168,13 +175,6 @@ final class SynthesisPlaybackQueueItem extends PlaybackQueueItem
// take() will return null since mStopped was true, and will then
// break out of the data write loop.
mReadReady.signal();
-
- // Wake up the synthesis thread if it was waiting on put(). Its
- // buffers will no longer be copied since mStopped is true. The
- // PlaybackSynthesisCallback that this synthesis corresponds to
- // would also have been stopped, and so all calls to
- // Callback.onDataAvailable( ) will return errors too.
- mNotFull.signal();
} finally {
mListLock.unlock();
}
diff --git a/core/java/android/text/OWNERS b/core/java/android/text/OWNERS
index 9f2182eca908..e56137119c28 100644
--- a/core/java/android/text/OWNERS
+++ b/core/java/android/text/OWNERS
@@ -1,3 +1,5 @@
+set noparent
+
siyamed@google.com
nona@google.com
clarabayarri@google.com
diff --git a/core/java/android/text/style/TypefaceSpan.java b/core/java/android/text/style/TypefaceSpan.java
index 162281250208..908de2988be9 100644
--- a/core/java/android/text/style/TypefaceSpan.java
+++ b/core/java/android/text/style/TypefaceSpan.java
@@ -17,6 +17,8 @@
package android.text.style;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.LeakyTypefaceStorage;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.os.Parcel;
@@ -25,33 +27,69 @@ import android.text.TextPaint;
import android.text.TextUtils;
/**
- * Changes the typeface family of the text to which the span is attached. Examples of typeface
- * family include "monospace", "serif", and "sans-serif".
+ * Span that updates the typeface of the text it's attached to. The <code>TypefaceSpan</code> can
+ * be constructed either based on a font family or based on a <code>Typeface</code>. When
+ * {@link #TypefaceSpan(String)} is used, the previous style of the <code>TextView</code> is kept.
+ * When {@link #TypefaceSpan(Typeface)} is used, the <code>Typeface</code> style replaces the
+ * <code>TextView</code>'s style.
* <p>
- * For example, change the typeface of a text to "monospace" like this:
+ * For example, let's consider a <code>TextView</code> with
+ * <code>android:textStyle="italic"</code> and a typeface created based on a font from resources,
+ * with a bold style. When applying a <code>TypefaceSpan</code> based the typeface, the text will
+ * only keep the bold style, overriding the <code>TextView</code>'s textStyle. When applying a
+ * <code>TypefaceSpan</code> based on a font family: "monospace", the resulted text will keep the
+ * italic style.
* <pre>
- * SpannableString string = new SpannableString("Text with typeface span");
- * string.setSpan(new TypefaceSpan("monospace"), 10, 18, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ * Typeface myTypeface = Typeface.create(ResourcesCompat.getFont(context, R.font.acme),
+ * Typeface.BOLD);
+ * SpannableString string = new SpannableString("Text with typeface span.");
+ * string.setSpan(new TypefaceSpan(myTypeface), 10, 18, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ * string.setSpan(new TypefaceSpan("monospace"), 19, 22, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
* </pre>
* <img src="{@docRoot}reference/android/images/text/style/typefacespan.png" />
- * <figcaption>Text with "monospace" typeface family.</figcaption>
+ * <figcaption>Text with <code>TypefaceSpan</code>s constructed based on a font from resource and
+ * from a font family.</figcaption>
*/
public class TypefaceSpan extends MetricAffectingSpan implements ParcelableSpan {
+ @Nullable
private final String mFamily;
+ @Nullable
+ private final Typeface mTypeface;
+
/**
- * Constructs a {@link TypefaceSpan} based on a font family.
+ * Constructs a {@link TypefaceSpan} based on the font family. The previous style of the
+ * TextPaint is kept. If the font family is null, the text paint is not modified.
*
- * @param family The font family for this typeface. Examples include
- * "monospace", "serif", and "sans-serif".
+ * @param family The font family for this typeface. Examples include
+ * "monospace", "serif", and "sans-serif"
*/
- public TypefaceSpan(String family) {
- mFamily = family;
+ public TypefaceSpan(@Nullable String family) {
+ this(family, null);
}
+ /**
+ * Constructs a {@link TypefaceSpan} from a {@link Typeface}. The previous style of the
+ * TextPaint is overridden and the style of the typeface is used.
+ *
+ * @param typeface the typeface
+ */
+ public TypefaceSpan(@NonNull Typeface typeface) {
+ this(null, typeface);
+ }
+
+ /**
+ * Constructs a {@link TypefaceSpan} from a parcel.
+ */
public TypefaceSpan(@NonNull Parcel src) {
mFamily = src.readString();
+ mTypeface = LeakyTypefaceStorage.readTypefaceFromParcel(src);
+ }
+
+ private TypefaceSpan(@Nullable String family, @Nullable Typeface typeface) {
+ mFamily = family;
+ mTypeface = typeface;
}
@Override
@@ -79,37 +117,59 @@ public class TypefaceSpan extends MetricAffectingSpan implements ParcelableSpan
@Override
public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
dest.writeString(mFamily);
+ LeakyTypefaceStorage.writeTypefaceToParcel(mTypeface, dest);
}
/**
- * Returns the font family name.
+ * Returns the font family name set in the span.
+ *
+ * @return the font family name
+ * @see #TypefaceSpan(String)
*/
+ @Nullable
public String getFamily() {
return mFamily;
}
+ /**
+ * Returns the typeface set in the span.
+ *
+ * @return the typeface set
+ * @see #TypefaceSpan(Typeface)
+ */
+ @Nullable
+ public Typeface getTypeface() {
+ return mTypeface;
+ }
+
@Override
- public void updateDrawState(@NonNull TextPaint textPaint) {
- apply(textPaint, mFamily);
+ public void updateDrawState(@NonNull TextPaint ds) {
+ updateTypeface(ds);
}
@Override
- public void updateMeasureState(@NonNull TextPaint textPaint) {
- apply(textPaint, mFamily);
+ public void updateMeasureState(@NonNull TextPaint paint) {
+ updateTypeface(paint);
}
- private static void apply(@NonNull Paint paint, String family) {
- int oldStyle;
+ private void updateTypeface(@NonNull Paint paint) {
+ if (mTypeface != null) {
+ paint.setTypeface(mTypeface);
+ } else if (mFamily != null) {
+ applyFontFamily(paint, mFamily);
+ }
+ }
+ private void applyFontFamily(@NonNull Paint paint, @NonNull String family) {
+ int style;
Typeface old = paint.getTypeface();
if (old == null) {
- oldStyle = 0;
+ style = Typeface.NORMAL;
} else {
- oldStyle = old.getStyle();
+ style = old.getStyle();
}
-
- Typeface tf = Typeface.create(family, oldStyle);
- int fake = oldStyle & ~tf.getStyle();
+ final Typeface styledTypeface = Typeface.create(family, style);
+ int fake = style & ~styledTypeface.getStyle();
if ((fake & Typeface.BOLD) != 0) {
paint.setFakeBoldText(true);
@@ -118,7 +178,6 @@ public class TypefaceSpan extends MetricAffectingSpan implements ParcelableSpan
if ((fake & Typeface.ITALIC) != 0) {
paint.setTextSkewX(-0.25f);
}
-
- paint.setTypeface(tf);
+ paint.setTypeface(styledTypeface);
}
}
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index d973d4ac076c..3a22db2bfb22 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -644,7 +644,13 @@ public class Linkify {
@Nullable Runnable modifyTextView) {
Preconditions.checkNotNull(text);
Preconditions.checkNotNull(classifier);
- final Supplier<TextLinks> supplier = () -> classifier.generateLinks(text, options);
+
+ // The input text may exceed the maximum length the text classifier can handle. In such
+ // cases, we process the text up to the maximum length.
+ final CharSequence truncatedText = text.subSequence(
+ 0, Math.min(text.length(), classifier.getMaxGenerateLinksTextLength()));
+
+ final Supplier<TextLinks> supplier = () -> classifier.generateLinks(truncatedText, options);
final Consumer<TextLinks> consumer = links -> {
if (links.getLinks().isEmpty()) {
if (callback != null) {
@@ -653,7 +659,8 @@ public class Linkify {
return;
}
- final TextLinkSpan[] old = text.getSpans(0, text.length(), TextLinkSpan.class);
+ // Remove spans only for the part of the text we generated links for.
+ final TextLinkSpan[] old = text.getSpans(0, truncatedText.length(), TextLinkSpan.class);
for (int i = old.length - 1; i >= 0; i--) {
text.removeSpan(old[i]);
}
@@ -662,7 +669,8 @@ public class Linkify {
? null : options.getSpanFactory();
final @TextLinks.ApplyStrategy int applyStrategy = (options == null)
? TextLinks.APPLY_STRATEGY_IGNORE : options.getApplyStrategy();
- final @TextLinks.Status int result = links.apply(text, applyStrategy, spanFactory);
+ final @TextLinks.Status int result = links.apply(text, applyStrategy, spanFactory,
+ true /*allowPrefix*/);
if (result == TextLinks.STATUS_LINKS_APPLIED) {
if (modifyTextView != null) {
modifyTextView.run();
diff --git a/core/java/android/transition/TransitionUtils.java b/core/java/android/transition/TransitionUtils.java
index 60b77bc8d426..46c9e0c7202f 100644
--- a/core/java/android/transition/TransitionUtils.java
+++ b/core/java/android/transition/TransitionUtils.java
@@ -20,14 +20,13 @@ import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.TypeEvaluator;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.Matrix;
+import android.graphics.Picture;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.view.DisplayListCanvas;
-import android.view.RenderNode;
-import android.view.ThreadedRenderer;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
@@ -128,10 +127,8 @@ public class TransitionUtils {
}
int bitmapWidth = (int) (width * scale);
int bitmapHeight = (int) (height * scale);
- final RenderNode node = RenderNode.create("TransitionUtils", hostView);
- node.setLeftTopRightBottom(0, 0, width, height);
- node.setClipToBounds(false);
- final DisplayListCanvas canvas = node.start(width, height);
+ final Picture picture = new Picture();
+ final Canvas canvas = picture.beginRecording(width, height);
// Do stuff with the canvas
Rect existingBounds = drawable.getBounds();
int left = existingBounds.left;
@@ -141,8 +138,8 @@ public class TransitionUtils {
drawable.setBounds(0, 0, bitmapWidth, bitmapHeight);
drawable.draw(canvas);
drawable.setBounds(left, top, right, bottom);
- node.end(canvas);
- return ThreadedRenderer.createHardwareBitmap(node, width, height);
+ picture.endRecording();
+ return Bitmap.createBitmap(picture);
}
/**
@@ -183,14 +180,12 @@ public class TransitionUtils {
matrix.postTranslate(-bounds.left, -bounds.top);
matrix.postScale(scale, scale);
- final RenderNode node = RenderNode.create("TransitionUtils", view);
- node.setLeftTopRightBottom(0, 0, bitmapWidth, bitmapHeight);
- node.setClipToBounds(false);
- final DisplayListCanvas canvas = node.start(bitmapWidth, bitmapHeight);
+ final Picture picture = new Picture();
+ final Canvas canvas = picture.beginRecording(bitmapWidth, bitmapHeight);
canvas.concat(matrix);
view.draw(canvas);
- node.end(canvas);
- bitmap = ThreadedRenderer.createHardwareBitmap(node, bitmapWidth, bitmapHeight);
+ picture.endRecording();
+ bitmap = Bitmap.createBitmap(picture);
}
if (addToOverlay) {
sceneRoot.getOverlay().remove(view);
diff --git a/core/java/android/util/ExceptionUtils.java b/core/java/android/util/ExceptionUtils.java
index da7387fcae70..1a397b39ef3c 100644
--- a/core/java/android/util/ExceptionUtils.java
+++ b/core/java/android/util/ExceptionUtils.java
@@ -86,4 +86,16 @@ public class ExceptionUtils {
while (t.getCause() != null) t = t.getCause();
return t;
}
-}
+
+ /**
+ * Appends {@code cause} at the end of the causal chain of {@code t}
+ *
+ * @return {@code t} for convenience
+ */
+ public static @NonNull Throwable appendCause(@NonNull Throwable t, @Nullable Throwable cause) {
+ if (cause != null) {
+ getRootCause(t).initCause(cause);
+ }
+ return t;
+ }
+} \ No newline at end of file
diff --git a/core/java/android/util/OWNERS b/core/java/android/util/OWNERS
new file mode 100644
index 000000000000..86ed1229b28e
--- /dev/null
+++ b/core/java/android/util/OWNERS
@@ -0,0 +1,2 @@
+per-file FeatureFlagUtils.java = sbasi@google.com
+per-file FeatureFlagUtils.java = zhfan@google.com
diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java
index 4805318385d5..3350f3e164bc 100644
--- a/core/java/android/util/StatsLog.java
+++ b/core/java/android/util/StatsLog.java
@@ -34,7 +34,7 @@ public final class StatsLog extends StatsLogInternal {
*/
public static boolean logStart(int label) {
if (label >= 0 && label < 16) {
- StatsLog.write(APP_HOOK, label, APP_HOOK__STATE__START);
+ StatsLog.write(APP_BREADCRUMB_REPORTED, label, APP_BREADCRUMB_REPORTED__STATE__START);
return true;
}
return false;
@@ -48,7 +48,7 @@ public final class StatsLog extends StatsLogInternal {
*/
public static boolean logStop(int label) {
if (label >= 0 && label < 16) {
- StatsLog.write(APP_HOOK, label, APP_HOOK__STATE__STOP);
+ StatsLog.write(APP_BREADCRUMB_REPORTED, label, APP_BREADCRUMB_REPORTED__STATE__STOP);
return true;
}
return false;
@@ -62,7 +62,8 @@ public final class StatsLog extends StatsLogInternal {
*/
public static boolean logEvent(int label) {
if (label >= 0 && label < 16) {
- StatsLog.write(APP_HOOK, label, APP_HOOK__STATE__UNSPECIFIED);
+ StatsLog.write(APP_BREADCRUMB_REPORTED, label,
+ APP_BREADCRUMB_REPORTED__STATE__UNSPECIFIED);
return true;
}
return false;
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index a61c8c1dba68..0b72c22d4e27 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -52,6 +52,16 @@ public final class DisplayCutout {
private static final String TAG = "DisplayCutout";
private static final String DP_MARKER = "@dp";
+ /**
+ * Category for overlays that allow emulating a display cutout on devices that don't have
+ * one.
+ *
+ * @see android.content.om.IOverlayManager
+ * @hide
+ */
+ public static final String EMULATION_OVERLAY_CATEGORY =
+ "com.android.internal.display_cutout_emulation";
+
private static final Rect ZERO_RECT = new Rect();
private static final Region EMPTY_REGION = new Region();
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index c4a716011765..d26a2f643ed4 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -158,7 +158,7 @@ public class RenderNodeAnimator extends Animator {
}
private void applyInterpolator() {
- if (mInterpolator == null) return;
+ if (mInterpolator == null || mNativePtr == null) return;
long ni;
if (isNativeInterpolator(mInterpolator)) {
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 370c97e37262..e50d40ef098f 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -331,6 +331,7 @@ public final class ThreadedRenderer {
private static final int FLAG_DUMP_FRAMESTATS = 1 << 0;
private static final int FLAG_DUMP_RESET = 1 << 1;
+ private static final int FLAG_DUMP_ALL = FLAG_DUMP_FRAMESTATS;
@IntDef(flag = true, prefix = { "FLAG_DUMP_" }, value = {
FLAG_DUMP_FRAMESTATS,
@@ -636,7 +637,10 @@ public final class ThreadedRenderer {
*/
void dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args) {
pw.flush();
- int flags = 0;
+ // If there's no arguments, eg 'dumpsys gfxinfo', then dump everything.
+ // If there's a targetted package, eg 'dumpsys gfxinfo com.android.systemui', then only
+ // dump the summary information
+ int flags = (args == null || args.length == 0) ? FLAG_DUMP_ALL : 0;
for (int i = 0; i < args.length; i++) {
switch (args[i]) {
case "framestats":
@@ -645,6 +649,9 @@ public final class ThreadedRenderer {
case "reset":
flags |= FLAG_DUMP_RESET;
break;
+ case "-a": // magic option passed when dumping a bugreport.
+ flags = FLAG_DUMP_ALL;
+ break;
}
}
nDumpProfileInfo(mNativeProxy, fd, flags);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2af246758812..3ff3c97620f0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7272,7 +7272,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// becomes true where it should issue notifyViewEntered().
afm.notifyViewEntered(this);
}
- } else if (!isFocused()) {
+ } else if (!enter && !isFocused()) {
afm.notifyViewExited(this);
}
}
@@ -8010,6 +8010,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* <li>Call {@link
* android.view.autofill.AutofillManager#notifyViewVisibilityChanged(View, int, boolean)}
* when the visibility of a virtual child changed.
+ * <li>Call
+ * {@link android.view.autofill.AutofillManager#notifyViewClicked(View, int)} when a virtual
+ * child is clicked.
* <li>Call {@link AutofillManager#commit()} when the autofill context of the view structure
* changed and the current context should be committed (for example, when the user tapped
* a {@code SUBMIT} button in an HTML page).
@@ -8807,6 +8810,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Computes whether this virtual autofill view is visible to the user.
*
+ * <p><b>Note: </b>By default it returns {@code true}, but views providing a virtual hierarchy
+ * view must override it.
+ *
* @return Whether the view is visible on the screen.
*/
public boolean isVisibleToUserForAutofill(int virtualId) {
@@ -8819,7 +8825,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
}
- return false;
+ return true;
}
/**
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index b09934e3e55f..276f50a51e66 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -21,7 +21,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Point;
+import android.graphics.Picture;
import android.graphics.Rect;
import android.os.Debug;
import android.os.Handler;
@@ -1782,27 +1782,18 @@ public class ViewDebug {
* @hide
*/
public static class HardwareCanvasProvider implements CanvasProvider {
-
- private View mView;
- private Point mSize;
- private RenderNode mNode;
- private DisplayListCanvas mCanvas;
+ private Picture mPicture;
@Override
public Canvas getCanvas(View view, int width, int height) {
- mView = view;
- mSize = new Point(width, height);
- mNode = RenderNode.create("ViewDebug", mView);
- mNode.setLeftTopRightBottom(0, 0, width, height);
- mNode.setClipToBounds(false);
- mCanvas = mNode.start(width, height);
- return mCanvas;
+ mPicture = new Picture();
+ return mPicture.beginRecording(width, height);
}
@Override
public Bitmap createBitmap() {
- mNode.end(mCanvas);
- return ThreadedRenderer.createHardwareBitmap(mNode, mSize.x, mSize.y);
+ mPicture.endRecording();
+ return Bitmap.createBitmap(mPicture);
}
}
diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java
index bb9e391ddcb4..7bae28a4e817 100644
--- a/core/java/android/view/WindowInfo.java
+++ b/core/java/android/view/WindowInfo.java
@@ -21,6 +21,7 @@ import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Pools;
+import android.view.accessibility.AccessibilityNodeInfo;
import java.util.ArrayList;
import java.util.List;
@@ -46,7 +47,7 @@ public class WindowInfo implements Parcelable {
public final Rect boundsInScreen = new Rect();
public List<IBinder> childTokens;
public CharSequence title;
- public int accessibilityIdOfAnchor = View.NO_ID;
+ public long accessibilityIdOfAnchor = AccessibilityNodeInfo.UNDEFINED_NODE_ID;
public boolean inPictureInPicture;
private WindowInfo() {
@@ -105,7 +106,7 @@ public class WindowInfo implements Parcelable {
parcel.writeInt(focused ? 1 : 0);
boundsInScreen.writeToParcel(parcel, flags);
parcel.writeCharSequence(title);
- parcel.writeInt(accessibilityIdOfAnchor);
+ parcel.writeLong(accessibilityIdOfAnchor);
parcel.writeInt(inPictureInPicture ? 1 : 0);
if (childTokens != null && !childTokens.isEmpty()) {
@@ -142,7 +143,7 @@ public class WindowInfo implements Parcelable {
focused = (parcel.readInt() == 1);
boundsInScreen.readFromParcel(parcel);
title = parcel.readCharSequence();
- accessibilityIdOfAnchor = parcel.readInt();
+ accessibilityIdOfAnchor = parcel.readLong();
inPictureInPicture = (parcel.readInt() == 1);
final boolean hasChildren = (parcel.readInt() == 1);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 1c5e87197750..c0a966602b0a 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -63,6 +63,7 @@ import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
+import android.view.accessibility.AccessibilityNodeInfo;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -2344,7 +2345,7 @@ public interface WindowManager extends ViewManager {
*
* @hide
*/
- public int accessibilityIdOfAnchor = -1;
+ public long accessibilityIdOfAnchor = AccessibilityNodeInfo.UNDEFINED_NODE_ID;
/**
* The window title isn't kept in sync with what is displayed in the title bar, so we
@@ -2538,7 +2539,7 @@ public interface WindowManager extends ViewManager {
out.writeInt(hasManualSurfaceInsets ? 1 : 0);
out.writeInt(preservePreviousSurfaceInsets ? 1 : 0);
out.writeInt(needsMenuKey);
- out.writeInt(accessibilityIdOfAnchor);
+ out.writeLong(accessibilityIdOfAnchor);
TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
out.writeInt(mColorMode);
out.writeLong(hideTimeoutMilliseconds);
@@ -2594,7 +2595,7 @@ public interface WindowManager extends ViewManager {
hasManualSurfaceInsets = in.readInt() != 0;
preservePreviousSurfaceInsets = in.readInt() != 0;
needsMenuKey = in.readInt();
- accessibilityIdOfAnchor = in.readInt();
+ accessibilityIdOfAnchor = in.readLong();
accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
mColorMode = in.readInt();
hideTimeoutMilliseconds = in.readLong();
diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java
index 990fbdb019d6..29f8442b2b46 100644
--- a/core/java/android/view/animation/AnimationUtils.java
+++ b/core/java/android/view/animation/AnimationUtils.java
@@ -18,6 +18,7 @@ package android.view.animation;
import android.annotation.AnimRes;
import android.annotation.InterpolatorRes;
+import android.annotation.TestApi;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
@@ -58,14 +59,43 @@ public class AnimationUtils {
}
};
- /** @hide */
+ /**
+ * Locks AnimationUtils{@link #currentAnimationTimeMillis()} to a fixed value for the current
+ * thread. This is used by {@link android.view.Choreographer} to ensure that all accesses
+ * during a vsync update are synchronized to the timestamp of the vsync.
+ *
+ * It is also exposed to tests to allow for rapid, flake-free headless testing.
+ *
+ * Must be followed by a call to {@link #unlockAnimationClock()} to allow time to
+ * progress. Failing to do this will result in stuck animations, scrolls, and flings.
+ *
+ * Note that time is not allowed to "rewind" and must perpetually flow forward. So the
+ * lock may fail if the time is in the past from a previously returned value, however
+ * time will be frozen for the duration of the lock. The clock is a thread-local, so
+ * ensure that {@link #lockAnimationClock(long)}, {@link #unlockAnimationClock()}, and
+ * {@link #currentAnimationTimeMillis()} are all called on the same thread.
+ *
+ * This is also not reference counted in any way. Any call to {@link #unlockAnimationClock()}
+ * will unlock the clock for everyone on the same thread. It is therefore recommended
+ * for tests to use their own thread to ensure that there is no collision with any existing
+ * {@link android.view.Choreographer} instance.
+ *
+ * @hide
+ * */
+ @TestApi
public static void lockAnimationClock(long vsyncMillis) {
AnimationState state = sAnimationState.get();
state.animationClockLocked = true;
state.currentVsyncTimeMillis = vsyncMillis;
}
- /** @hide */
+ /**
+ * Frees the time lock set in place by {@link #lockAnimationClock(long)}. Must be called
+ * to allow the animation clock to self-update.
+ *
+ * @hide
+ */
+ @TestApi
public static void unlockAnimationClock() {
sAnimationState.get().animationClockLocked = false;
}
diff --git a/core/java/android/view/autofill/AutofillId.java b/core/java/android/view/autofill/AutofillId.java
index 5ce2421aac87..cb1d89c54d9a 100644
--- a/core/java/android/view/autofill/AutofillId.java
+++ b/core/java/android/view/autofill/AutofillId.java
@@ -38,6 +38,7 @@ public final class AutofillId implements Parcelable {
}
/** @hide */
+ @TestApi
public AutofillId(AutofillId parent, int virtualChildId) {
mVirtual = true;
mViewId = parent.mViewId;
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 8b64bad8fe62..7792fa640015 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -24,6 +24,7 @@ import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
import android.annotation.SystemService;
import android.content.ComponentName;
import android.content.Context;
@@ -71,10 +72,9 @@ import java.util.Collections;
import java.util.List;
import java.util.Objects;
+//TODO: use java.lang.ref.Cleaner once Android supports Java 9
import sun.misc.Cleaner;
-// TODO: use java.lang.ref.Cleaner once Android supports Java 9
-
/**
* The {@link AutofillManager} provides ways for apps and custom views to integrate with the
* Autofill Framework lifecycle.
@@ -136,6 +136,7 @@ import sun.misc.Cleaner;
* <p>It is safe to call into its methods from any thread.
*/
@SystemService(Context.AUTOFILL_MANAGER_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_AUTOFILL)
public final class AutofillManager {
private static final String TAG = "AutofillManager";
@@ -356,6 +357,13 @@ public final class AutofillManager {
@GuardedBy("mLock")
@Nullable private ArraySet<AutofillId> mFillableIds;
+ /**
+ * Views that were already "entered" - if they're entered again when the session is not active,
+ * they're ignored
+ * */
+ @GuardedBy("mLock")
+ @Nullable private ArraySet<AutofillId> mEnteredIds;
+
/** If set, session is commited when the field is clicked. */
@GuardedBy("mLock")
@Nullable private AutofillId mSaveTriggerId;
@@ -711,17 +719,29 @@ public final class AutofillManager {
}
@GuardedBy("mLock")
- private boolean shouldIgnoreViewEnteredLocked(@NonNull View view, int flags) {
+ private boolean shouldIgnoreViewEnteredLocked(@NonNull AutofillId id, int flags) {
if (isDisabledByServiceLocked()) {
if (sVerbose) {
- Log.v(TAG, "ignoring notifyViewEntered(flags=" + flags + ", view=" + view
- + ") on state " + getStateAsStringLocked());
+ Log.v(TAG, "ignoring notifyViewEntered(flags=" + flags + ", view=" + id
+ + ") on state " + getStateAsStringLocked() + " because disabled by svc");
}
return true;
}
- if (sVerbose && isFinishedLocked()) {
- Log.v(TAG, "not ignoring notifyViewEntered(flags=" + flags + ", view=" + view
- + ") on state " + getStateAsStringLocked());
+ if (isFinishedLocked()) {
+ // Session already finished: ignore if automatic request and view already entered
+ if ((flags & FLAG_MANUAL_REQUEST) == 0 && mEnteredIds != null
+ && mEnteredIds.contains(id)) {
+ if (sVerbose) {
+ Log.v(TAG, "ignoring notifyViewEntered(flags=" + flags + ", view=" + id
+ + ") on state " + getStateAsStringLocked()
+ + " because view was already entered: " + mEnteredIds);
+ }
+ return true;
+ }
+ }
+ if (sVerbose) {
+ Log.v(TAG, "not ignoring notifyViewEntered(flags=" + flags + ", view=" + id
+ + ", state " + getStateAsStringLocked() + ", enteredIds=" + mEnteredIds);
}
return false;
}
@@ -753,7 +773,8 @@ public final class AutofillManager {
/** Returns AutofillCallback if need fire EVENT_INPUT_UNAVAILABLE */
@GuardedBy("mLock")
private AutofillCallback notifyViewEnteredLocked(@NonNull View view, int flags) {
- if (shouldIgnoreViewEnteredLocked(view, flags)) return null;
+ final AutofillId id = getAutofillId(view);
+ if (shouldIgnoreViewEnteredLocked(id, flags)) return null;
AutofillCallback callback = null;
@@ -766,7 +787,6 @@ public final class AutofillManager {
} else {
// don't notify entered when Activity is already in background
if (!isClientDisablingEnterExitEvent()) {
- final AutofillId id = getAutofillId(view);
final AutofillValue value = view.getAutofillValue();
if (!isActiveLocked()) {
@@ -776,6 +796,7 @@ public final class AutofillManager {
// Update focus on existing session.
updateSessionLocked(id, null, value, ACTION_VIEW_ENTERED, flags);
}
+ addEnteredIdLocked(id);
}
}
return callback;
@@ -900,8 +921,9 @@ public final class AutofillManager {
@GuardedBy("mLock")
private AutofillCallback notifyViewEnteredLocked(View view, int virtualId, Rect bounds,
int flags) {
+ final AutofillId id = getAutofillId(view, virtualId);
AutofillCallback callback = null;
- if (shouldIgnoreViewEnteredLocked(view, flags)) return callback;
+ if (shouldIgnoreViewEnteredLocked(id, flags)) return callback;
ensureServiceClientAddedIfNeededLocked();
@@ -912,8 +934,6 @@ public final class AutofillManager {
} else {
// don't notify entered when Activity is already in background
if (!isClientDisablingEnterExitEvent()) {
- final AutofillId id = getAutofillId(view, virtualId);
-
if (!isActiveLocked()) {
// Starts new session.
startSessionLocked(id, bounds, null, flags);
@@ -921,11 +941,20 @@ public final class AutofillManager {
// Update focus on existing session.
updateSessionLocked(id, bounds, null, ACTION_VIEW_ENTERED, flags);
}
+ addEnteredIdLocked(id);
}
}
return callback;
}
+ @GuardedBy("mLock")
+ private void addEnteredIdLocked(@NonNull AutofillId id) {
+ if (mEnteredIds == null) {
+ mEnteredIds = new ArraySet<>(1);
+ }
+ mEnteredIds.add(id);
+ }
+
/**
* Called when a virtual view that supports autofill is exited.
*
@@ -992,9 +1021,9 @@ public final class AutofillManager {
}
if (!mEnabled || !isActiveLocked()) {
- if (sVerbose && mEnabled) {
- Log.v(TAG, "notifyValueChanged(" + view + "): ignoring on state "
- + getStateAsStringLocked());
+ if (sVerbose) {
+ Log.v(TAG, "notifyValueChanged(" + view.getAutofillId()
+ + "): ignoring on state " + getStateAsStringLocked());
}
return;
}
@@ -1024,6 +1053,10 @@ public final class AutofillManager {
}
synchronized (mLock) {
if (!mEnabled || !isActiveLocked()) {
+ if (sVerbose) {
+ Log.v(TAG, "notifyValueChanged(" + view.getAutofillId() + ":" + virtualId
+ + "): ignoring on state " + getStateAsStringLocked());
+ }
return;
}
@@ -1032,18 +1065,35 @@ public final class AutofillManager {
}
}
+ /**
+ * Called to indicate a {@link View} is clicked.
+ *
+ * @param view view that has been clicked.
+ */
+ public void notifyViewClicked(@NonNull View view) {
+ notifyViewClicked(view.getAutofillId());
+ }
/**
- * Called when a {@link View} is clicked. Currently only used by views that should trigger save.
+ * Called to indicate a virtual view has been clicked.
*
- * @hide
+ * @param view the virtual view parent.
+ * @param virtualId id identifying the virtual child inside the parent view.
*/
- public void notifyViewClicked(View view) {
- final AutofillId id = view.getAutofillId();
+ public void notifyViewClicked(@NonNull View view, int virtualId) {
+ notifyViewClicked(getAutofillId(view, virtualId));
+ }
+ private void notifyViewClicked(AutofillId id) {
+ if (!hasAutofillFeature()) {
+ return;
+ }
if (sVerbose) Log.v(TAG, "notifyViewClicked(): id=" + id + ", trigger=" + mSaveTriggerId);
synchronized (mLock) {
+ if (!mEnabled || !isActiveLocked()) {
+ return;
+ }
if (mSaveTriggerId != null && mSaveTriggerId.equals(id)) {
if (sDebug) Log.d(TAG, "triggering commit by click of " + id);
commitLocked();
@@ -1058,16 +1108,16 @@ public final class AutofillManager {
*
* @hide
*/
- public void onActivityFinished() {
+ public void onActivityFinishing() {
if (!hasAutofillFeature()) {
return;
}
synchronized (mLock) {
if (mSaveOnFinish) {
- if (sDebug) Log.d(TAG, "Committing session on finish() as requested by service");
+ if (sDebug) Log.d(TAG, "onActivityFinishing(): calling commitLocked()");
commitLocked();
} else {
- if (sDebug) Log.d(TAG, "Cancelling session on finish() as requested by service");
+ if (sDebug) Log.d(TAG, "onActivityFinishing(): calling cancelLocked()");
cancelLocked();
}
}
@@ -1088,6 +1138,7 @@ public final class AutofillManager {
if (!hasAutofillFeature()) {
return;
}
+ if (sVerbose) Log.v(TAG, "commit() called by app");
synchronized (mLock) {
commitLocked();
}
@@ -1392,7 +1443,8 @@ public final class AutofillManager {
if (sVerbose) {
Log.v(TAG, "startSessionLocked(): id=" + id + ", bounds=" + bounds + ", value=" + value
+ ", flags=" + flags + ", state=" + getStateAsStringLocked()
- + ", compatMode=" + isCompatibilityModeEnabledLocked());
+ + ", compatMode=" + isCompatibilityModeEnabledLocked()
+ + ", enteredIds=" + mEnteredIds);
}
if (mState != STATE_UNKNOWN && !isFinishedLocked() && (flags & FLAG_MANUAL_REQUEST) == 0) {
if (sVerbose) {
@@ -1407,7 +1459,8 @@ public final class AutofillManager {
mSessionId = mService.startSession(client.autofillClientGetActivityToken(),
mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
- mCallback != null, flags, client.autofillClientGetComponentName());
+ mCallback != null, flags, client.autofillClientGetComponentName(),
+ isCompatibilityModeEnabledLocked());
if (mSessionId != NO_SESSION) {
mState = STATE_ACTIVE;
}
@@ -1429,7 +1482,7 @@ public final class AutofillManager {
throw e.rethrowFromSystemServer();
}
- resetSessionLocked();
+ resetSessionLocked(/* resetEnteredIds= */ true);
}
@GuardedBy("mLock")
@@ -1444,22 +1497,25 @@ public final class AutofillManager {
throw e.rethrowFromSystemServer();
}
- resetSessionLocked();
+ resetSessionLocked(/* resetEnteredIds= */ true);
}
@GuardedBy("mLock")
- private void resetSessionLocked() {
+ private void resetSessionLocked(boolean resetEnteredIds) {
mSessionId = NO_SESSION;
mState = STATE_UNKNOWN;
mTrackedViews = null;
mFillableIds = null;
mSaveTriggerId = null;
+ if (resetEnteredIds) {
+ mEnteredIds = null;
+ }
}
@GuardedBy("mLock")
private void updateSessionLocked(AutofillId id, Rect bounds, AutofillValue value, int action,
int flags) {
- if (sVerbose && action != ACTION_VIEW_EXITED) {
+ if (sVerbose) {
Log.v(TAG, "updateSessionLocked(): id=" + id + ", bounds=" + bounds
+ ", value=" + value + ", action=" + action + ", flags=" + flags);
}
@@ -1474,7 +1530,7 @@ public final class AutofillManager {
client.autofillClientGetActivityToken(),
mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
mCallback != null, flags, client.autofillClientGetComponentName(),
- mSessionId, action);
+ mSessionId, action, isCompatibilityModeEnabledLocked());
if (newId != mSessionId) {
if (sDebug) Log.d(TAG, "Session restarted: " + mSessionId + "=>" + newId);
mSessionId = newId;
@@ -1629,7 +1685,7 @@ public final class AutofillManager {
mEnabled = (flags & SET_STATE_FLAG_ENABLED) != 0;
if (!mEnabled || (flags & SET_STATE_FLAG_RESET_SESSION) != 0) {
// Reset the session state
- resetSessionLocked();
+ resetSessionLocked(/* resetEnteredIds= */ true);
}
if ((flags & SET_STATE_FLAG_RESET_CLIENT) != 0) {
// Reset connection to system
@@ -1825,7 +1881,7 @@ public final class AutofillManager {
private void setSessionFinished(int newState) {
synchronized (mLock) {
if (sVerbose) Log.v(TAG, "setSessionFinished(): from " + mState + " to " + newState);
- resetSessionLocked();
+ resetSessionLocked(/* resetEnteredIds= */ false);
mState = newState;
}
}
@@ -1953,6 +2009,7 @@ public final class AutofillManager {
pw.print(pfx2); pw.print("invisible:"); pw.println(mTrackedViews.mInvisibleTrackedIds);
}
pw.print(pfx); pw.print("fillable ids: "); pw.println(mFillableIds);
+ pw.print(pfx); pw.print("entered ids: "); pw.println(mEnteredIds);
pw.print(pfx); pw.print("save trigger id: "); pw.println(mSaveTriggerId);
pw.print(pfx); pw.print("save on finish(): "); pw.println(mSaveOnFinish);
pw.print(pfx); pw.print("compat mode enabled: "); pw.println(
@@ -2295,6 +2352,7 @@ public final class AutofillManager {
final boolean[] isVisible;
if (client.autofillClientIsVisibleForAutofill()) {
+ if (sVerbose) Log.v(TAG, "client is visible, check tracked ids");
isVisible = client.autofillClientGetViewVisibility(trackedIds);
} else {
// All false
@@ -2314,7 +2372,7 @@ public final class AutofillManager {
}
if (sVerbose) {
- Log.v(TAG, "TrackedViews(trackedIds=" + trackedIds + "): "
+ Log.v(TAG, "TrackedViews(trackedIds=" + Arrays.toString(trackedIds) + "): "
+ " mVisibleTrackedIds=" + mVisibleTrackedIds
+ " mInvisibleTrackedIds=" + mInvisibleTrackedIds);
}
@@ -2420,6 +2478,9 @@ public final class AutofillManager {
}
if (mVisibleTrackedIds == null) {
+ if (sVerbose) {
+ Log.v(TAG, "onVisibleForAutofillChangedLocked(): no more visible ids");
+ }
finishSessionLocked();
}
}
diff --git a/core/java/android/view/autofill/AutofillPopupWindow.java b/core/java/android/view/autofill/AutofillPopupWindow.java
index e80fdd93542c..1da998d01ba3 100644
--- a/core/java/android/view/autofill/AutofillPopupWindow.java
+++ b/core/java/android/view/autofill/AutofillPopupWindow.java
@@ -46,6 +46,7 @@ public class AutofillPopupWindow extends PopupWindow {
private final WindowPresenter mWindowPresenter;
private WindowManager.LayoutParams mWindowLayoutParams;
+ private boolean mFullScreen;
private final View.OnAttachStateChangeListener mOnAttachStateChangeListener =
new View.OnAttachStateChangeListener() {
@@ -104,12 +105,17 @@ public class AutofillPopupWindow extends PopupWindow {
*/
public void update(View anchor, int offsetX, int offsetY, int width, int height,
Rect virtualBounds) {
+ mFullScreen = width == LayoutParams.MATCH_PARENT && height == LayoutParams.MATCH_PARENT;
// If we are showing the popup for a virtual view we use a fake view which
// delegates to the anchor but present itself with the same bounds as the
// virtual view. This ensures that the location logic in popup works
// symmetrically when the dropdown is below and above the anchor.
final View actualAnchor;
- if (virtualBounds != null) {
+ if (mFullScreen) {
+ offsetX = 0;
+ offsetY = 0;
+ actualAnchor = anchor;
+ } else if (virtualBounds != null) {
final int[] mLocationOnScreen = new int[] {virtualBounds.left, virtualBounds.top};
actualAnchor = new View(anchor.getContext()) {
@Override
@@ -209,6 +215,17 @@ public class AutofillPopupWindow extends PopupWindow {
}
@Override
+ protected boolean findDropDownPosition(View anchor, LayoutParams outParams,
+ int xOffset, int yOffset, int width, int height, int gravity, boolean allowScroll) {
+ if (mFullScreen) {
+ // Do not patch LayoutParams if force full screen
+ return false;
+ }
+ return super.findDropDownPosition(anchor, outParams, xOffset, yOffset,
+ width, height, gravity, allowScroll);
+ }
+
+ @Override
public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) {
if (sVerbose) {
Log.v(TAG, "showAsDropDown(): anchor=" + anchor + ", xoff=" + xoff + ", yoff=" + yoff
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 001854716715..56f79abf6c19 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -38,7 +38,7 @@ interface IAutoFillManager {
void removeClient(in IAutoFillManagerClient client, int userId);
int startSession(IBinder activityToken, in IBinder appCallback, in AutofillId autoFillId,
in Rect bounds, in AutofillValue value, int userId, boolean hasCallback, int flags,
- in ComponentName componentName);
+ in ComponentName componentName, boolean compatMode);
FillEventHistory getFillEventHistory();
boolean restoreSession(int sessionId, in IBinder activityToken, in IBinder appCallback);
void updateSession(int sessionId, in AutofillId id, in Rect bounds,
@@ -46,7 +46,7 @@ interface IAutoFillManager {
int updateOrRestartSession(IBinder activityToken, in IBinder appCallback,
in AutofillId autoFillId, in Rect bounds, in AutofillValue value, int userId,
boolean hasCallback, int flags, in ComponentName componentName, int sessionId,
- int action);
+ int action, boolean compatMode);
void finishSession(int sessionId, int userId);
void cancelSession(int sessionId, int userId);
void setAuthenticationResult(in Bundle data, int sessionId, int authenticationId, int userId);
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 9de26a86f20f..a2280a4acd11 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -20,10 +20,12 @@ import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.inputmethodservice.InputMethodService;
import android.net.Uri;
@@ -213,6 +215,7 @@ import java.util.concurrent.TimeUnit;
* </ul>
*/
@SystemService(Context.INPUT_METHOD_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_INPUT_METHODS)
public final class InputMethodManager {
static final boolean DEBUG = false;
static final String TAG = "InputMethodManager";
diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java
index af55dcd0ed72..cbc3828ba56e 100644
--- a/core/java/android/view/textclassifier/SystemTextClassifier.java
+++ b/core/java/android/view/textclassifier/SystemTextClassifier.java
@@ -121,6 +121,15 @@ final class SystemTextClassifier implements TextClassifier {
return mFallback.generateLinks(text, options);
}
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public int getMaxGenerateLinksTextLength() {
+ // TODO: retrieve this from the bound service.
+ return mFallback.getMaxGenerateLinksTextLength();
+ }
+
private static final class TextSelectionCallback extends ITextSelectionCallback.Stub {
final ResponseReceiver<TextSelection> mReceiver = new ResponseReceiver<>();
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index 9f75c4a80ca2..2a62f23f19c7 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -276,9 +276,11 @@ public interface TextClassifier {
* @param text the text to generate annotations for
* @param options configuration for link generation
*
- * @throws IllegalArgumentException if text is null
+ * @throws IllegalArgumentException if text is null or the text is too long for the
+ * TextClassifier implementation.
*
* @see #generateLinks(CharSequence)
+ * @see #getMaxGenerateLinksTextLength()
*/
@WorkerThread
default TextLinks generateLinks(
@@ -299,9 +301,11 @@ public interface TextClassifier {
*
* @param text the text to generate annotations for
*
- * @throws IllegalArgumentException if text is null
+ * @throws IllegalArgumentException if text is null or the text is too long for the
+ * TextClassifier implementation.
*
* @see #generateLinks(CharSequence, TextLinks.Options)
+ * @see #getMaxGenerateLinksTextLength()
*/
@WorkerThread
default TextLinks generateLinks(@NonNull CharSequence text) {
@@ -309,6 +313,16 @@ public interface TextClassifier {
}
/**
+ * Returns the maximal length of text that can be processed by generateLinks.
+ *
+ * @see #generateLinks(CharSequence)
+ * @see #generateLinks(CharSequence, TextLinks.Options)
+ */
+ default int getMaxGenerateLinksTextLength() {
+ return Integer.MAX_VALUE;
+ }
+
+ /**
* Returns a {@link Collection} of the entity types in the specified preset.
*
* @see #ENTITY_PRESET_ALL
@@ -461,6 +475,15 @@ public interface TextClassifier {
checkMainThread(allowInMainThread);
}
+ /**
+ * @throws IllegalArgumentException if text is null; the text is too long or options is null
+ */
+ public static void validate(@NonNull CharSequence text, int maxLength,
+ boolean allowInMainThread) {
+ validate(text, allowInMainThread);
+ Preconditions.checkArgumentInRange(text.length(), 0, maxLength, "text.length()");
+ }
+
private static void checkMainThread(boolean allowInMainThread) {
if (!allowInMainThread && Looper.myLooper() == Looper.getMainLooper()) {
Slog.w(DEFAULT_LOG_TAG, "TextClassifier called on main thread");
diff --git a/core/java/android/view/textclassifier/TextClassifierConstants.java b/core/java/android/view/textclassifier/TextClassifierConstants.java
index 00695b797cb3..efa69488521f 100644
--- a/core/java/android/view/textclassifier/TextClassifierConstants.java
+++ b/core/java/android/view/textclassifier/TextClassifierConstants.java
@@ -47,10 +47,19 @@ public final class TextClassifierConstants {
"smart_selection_enabled_for_edit_text";
private static final String SMART_LINKIFY_ENABLED =
"smart_linkify_enabled";
+ private static final String SUGGEST_SELECTION_MAX_RANGE_LENGTH =
+ "suggest_selection_max_range_length";
+ private static final String CLASSIFY_TEXT_MAX_RANGE_LENGTH =
+ "classify_text_max_range_length";
+ private static final String GENERATE_LINKS_MAX_TEXT_LENGTH =
+ "generate_links_max_text_length";
private static final boolean SMART_SELECTION_DARK_LAUNCH_DEFAULT = false;
private static final boolean SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT = true;
private static final boolean SMART_LINKIFY_ENABLED_DEFAULT = true;
+ private static final int SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT = 10 * 1000;
+ private static final int CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT = 10 * 1000;
+ private static final int GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT = 100 * 1000;
/** Default settings. */
static final TextClassifierConstants DEFAULT = new TextClassifierConstants();
@@ -58,11 +67,17 @@ public final class TextClassifierConstants {
private final boolean mDarkLaunch;
private final boolean mSuggestSelectionEnabledForEditableText;
private final boolean mSmartLinkifyEnabled;
+ private final int mSuggestSelectionMaxRangeLength;
+ private final int mClassifyTextMaxRangeLength;
+ private final int mGenerateLinksMaxTextLength;
private TextClassifierConstants() {
mDarkLaunch = SMART_SELECTION_DARK_LAUNCH_DEFAULT;
mSuggestSelectionEnabledForEditableText = SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT;
mSmartLinkifyEnabled = SMART_LINKIFY_ENABLED_DEFAULT;
+ mSuggestSelectionMaxRangeLength = SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT;
+ mClassifyTextMaxRangeLength = CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT;
+ mGenerateLinksMaxTextLength = GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT;
}
private TextClassifierConstants(@Nullable String settings) {
@@ -82,6 +97,15 @@ public final class TextClassifierConstants {
mSmartLinkifyEnabled = parser.getBoolean(
SMART_LINKIFY_ENABLED,
SMART_LINKIFY_ENABLED_DEFAULT);
+ mSuggestSelectionMaxRangeLength = parser.getInt(
+ SUGGEST_SELECTION_MAX_RANGE_LENGTH,
+ SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT);
+ mClassifyTextMaxRangeLength = parser.getInt(
+ CLASSIFY_TEXT_MAX_RANGE_LENGTH,
+ CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT);
+ mGenerateLinksMaxTextLength = parser.getInt(
+ GENERATE_LINKS_MAX_TEXT_LENGTH,
+ GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT);
}
static TextClassifierConstants loadFromString(String settings) {
@@ -99,4 +123,16 @@ public final class TextClassifierConstants {
public boolean isSmartLinkifyEnabled() {
return mSmartLinkifyEnabled;
}
+
+ public int getSuggestSelectionMaxRangeLength() {
+ return mSuggestSelectionMaxRangeLength;
+ }
+
+ public int getClassifyTextMaxRangeLength() {
+ return mClassifyTextMaxRangeLength;
+ }
+
+ public int getGenerateLinksMaxTextLength() {
+ return mGenerateLinksMaxTextLength;
+ }
}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index fc034937312c..795caffd04d5 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -128,7 +128,9 @@ public final class TextClassifierImpl implements TextClassifier {
@Nullable TextSelection.Options options) {
Utils.validate(text, selectionStartIndex, selectionEndIndex, false /* allowInMainThread */);
try {
- if (text.length() > 0) {
+ final int rangeLength = selectionEndIndex - selectionStartIndex;
+ if (text.length() > 0
+ && rangeLength <= getSettings().getSuggestSelectionMaxRangeLength()) {
final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
final boolean darkLaunchAllowed = options != null && options.isDarkLaunchAllowed();
final SmartSelection smartSelection = getSmartSelection(locales);
@@ -183,7 +185,8 @@ public final class TextClassifierImpl implements TextClassifier {
@Nullable TextClassification.Options options) {
Utils.validate(text, startIndex, endIndex, false /* allowInMainThread */);
try {
- if (text.length() > 0) {
+ final int rangeLength = endIndex - startIndex;
+ if (text.length() > 0 && rangeLength <= getSettings().getClassifyTextMaxRangeLength()) {
final String string = text.toString();
final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
final Calendar refTime = (options == null) ? null : options.getReferenceTime();
@@ -207,7 +210,7 @@ public final class TextClassifierImpl implements TextClassifier {
@Override
public TextLinks generateLinks(
@NonNull CharSequence text, @Nullable TextLinks.Options options) {
- Utils.validate(text, false /* allowInMainThread */);
+ Utils.validate(text, getMaxGenerateLinksTextLength(), false /* allowInMainThread */);
final String textString = text.toString();
final TextLinks.Builder builder = new TextLinks.Builder(textString);
@@ -241,6 +244,12 @@ public final class TextClassifierImpl implements TextClassifier {
return mFallback.generateLinks(text, options);
}
+ /** @inheritDoc */
+ @Override
+ public int getMaxGenerateLinksTextLength() {
+ return getSettings().getGenerateLinksMaxTextLength();
+ }
+
@Override
public Collection<String> getEntitiesForPreset(@TextClassifier.EntityPreset int entityPreset) {
switch (entityPreset) {
diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java
index d866d1305172..3d252f293663 100644
--- a/core/java/android/view/textclassifier/TextLinks.java
+++ b/core/java/android/view/textclassifier/TextLinks.java
@@ -108,6 +108,7 @@ public final class TextLinks implements Parcelable {
* @param text the text to apply the links to. Must match the original text
* @param applyStrategy strategy for resolving link conflicts
* @param spanFactory a factory to generate spans from TextLinks. Will use a default if null
+ * @param allowPrefix whether to allow applying links only to a prefix of the text.
*
* @return a status code indicating whether or not the links were successfully applied
*
@@ -117,10 +118,12 @@ public final class TextLinks implements Parcelable {
public int apply(
@NonNull Spannable text,
@ApplyStrategy int applyStrategy,
- @Nullable Function<TextLink, TextLinkSpan> spanFactory) {
+ @Nullable Function<TextLink, TextLinkSpan> spanFactory,
+ boolean allowPrefix) {
Preconditions.checkNotNull(text);
checkValidApplyStrategy(applyStrategy);
- if (!mFullText.equals(text.toString())) {
+ final String textString = text.toString();
+ if (!mFullText.equals(textString) && !(allowPrefix && textString.startsWith(mFullText))) {
return STATUS_DIFFERENT_TEXT;
}
if (mLinks.isEmpty()) {
diff --git a/core/java/android/webkit/TracingConfig.java b/core/java/android/webkit/TracingConfig.java
index 75e2bf7026c5..68badecaec3a 100644
--- a/core/java/android/webkit/TracingConfig.java
+++ b/core/java/android/webkit/TracingConfig.java
@@ -21,61 +21,76 @@ import android.annotation.NonNull;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
/**
* Holds tracing configuration information and predefined settings.
*/
public class TracingConfig {
- private final String mCustomCategoryPattern;
- private final @PresetCategories int mPresetCategories;
+ private @PredefinedCategories int mPredefinedCategories;
+ private final List<String> mCustomIncludedCategories = new ArrayList<String>();
private @TracingMode int mTracingMode;
/** @hide */
- @IntDef({CATEGORIES_NONE, CATEGORIES_WEB_DEVELOPER, CATEGORIES_INPUT_LATENCY,
- CATEGORIES_RENDERING, CATEGORIES_JAVASCRIPT_AND_RENDERING, CATEGORIES_FRAME_VIEWER})
+ @IntDef(flag = true, value = {CATEGORIES_NONE, CATEGORIES_WEB_DEVELOPER,
+ CATEGORIES_INPUT_LATENCY, CATEGORIES_RENDERING, CATEGORIES_JAVASCRIPT_AND_RENDERING,
+ CATEGORIES_FRAME_VIEWER})
@Retention(RetentionPolicy.SOURCE)
- public @interface PresetCategories {}
+ public @interface PredefinedCategories {}
/**
- * Indicates that there are no preset categories.
+ * Indicates that there are no predefined categories.
*/
- public static final int CATEGORIES_NONE = -1;
+ public static final int CATEGORIES_NONE = 0;
/**
- * Predefined categories typically useful for web developers.
+ * Predefined set of categories, includes all categories enabled by default in chromium.
+ * Use with caution: this setting may produce large trace output.
+ */
+ public static final int CATEGORIES_ALL = 1 << 0;
+
+ /**
+ * Predefined set of categories typically useful for analyzing WebViews.
+ * Typically includes android_webview and Java.
+ */
+ public static final int CATEGORIES_ANDROID_WEBVIEW = 1 << 1;
+
+ /**
+ * Predefined set of categories typically useful for web developers.
* Typically includes blink, compositor, renderer.scheduler and v8 categories.
*/
- public static final int CATEGORIES_WEB_DEVELOPER = 0;
+ public static final int CATEGORIES_WEB_DEVELOPER = 1 << 2;
/**
- * Predefined categories for analyzing input latency issues.
+ * Predefined set of categories for analyzing input latency issues.
* Typically includes input, renderer.scheduler categories.
*/
- public static final int CATEGORIES_INPUT_LATENCY = 1;
+ public static final int CATEGORIES_INPUT_LATENCY = 1 << 3;
/**
- * Predefined categories for analyzing rendering issues.
+ * Predefined set of categories for analyzing rendering issues.
* Typically includes blink, compositor and gpu categories.
*/
- public static final int CATEGORIES_RENDERING = 2;
+ public static final int CATEGORIES_RENDERING = 1 << 4;
/**
- * Predefined categories for analyzing javascript and rendering issues.
- * Typically includes blink, compositor, gpu, renderer.schduler and v8 categories.
+ * Predefined set of categories for analyzing javascript and rendering issues.
+ * Typically includes blink, compositor, gpu, renderer.scheduler and v8 categories.
*/
- public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 3;
+ public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 1 << 5;
/**
- * Predefined categories for studying difficult rendering performance problems.
+ * Predefined set of categories for studying difficult rendering performance problems.
* Typically includes blink, compositor, gpu, renderer.scheduler, v8 and
* some other compositor categories which are disabled by default.
*/
- public static final int CATEGORIES_FRAME_VIEWER = 4;
+ public static final int CATEGORIES_FRAME_VIEWER = 1 << 6;
/** @hide */
- @IntDef({RECORD_UNTIL_FULL, RECORD_CONTINUOUSLY, RECORD_UNTIL_FULL_LARGE_BUFFER,
- RECORD_TO_CONSOLE})
+ @IntDef({RECORD_UNTIL_FULL, RECORD_CONTINUOUSLY, RECORD_UNTIL_FULL_LARGE_BUFFER})
@Retention(RetentionPolicy.SOURCE)
public @interface TracingMode {}
@@ -97,99 +112,38 @@ public class TracingConfig {
/**
* Record trace events using a larger internal tracing buffer until it is full.
- * Uses more memory than the other modes and may not be suitable on devices
- * with smaller RAM. Depending on the implementation typically allows up to
- * 512 million events to be stored.
+ * Uses significantly more memory than {@link #RECORD_UNTIL_FULL} and may not be
+ * suitable on devices with smaller RAM.
*/
public static final int RECORD_UNTIL_FULL_LARGE_BUFFER = 2;
/**
- * Record trace events to console (logcat). The events are discarded and nothing
- * is sent back to the caller. Uses the least memory as compared to the other modes.
- */
- public static final int RECORD_TO_CONSOLE = 3;
-
- /**
- * Create config with the preset categories.
- * <p>
- * Example:
- * TracingConfig(CATEGORIES_WEB_DEVELOPER) -- records trace events from the "web developer"
- * preset categories.
- *
- * @param presetCategories preset categories to use, one of {@link #CATEGORIES_WEB_DEVELOPER},
- * {@link #CATEGORIES_INPUT_LATENCY}, {@link #CATEGORIES_RENDERING},
- * {@link #CATEGORIES_JAVASCRIPT_AND_RENDERING} or
- * {@link #CATEGORIES_FRAME_VIEWER}.
- *
- * Note: for specifying custom categories without presets use
- * {@link #TracingConfig(int, String, int)}.
- *
+ * @hide
*/
- public TracingConfig(@PresetCategories int presetCategories) {
- this(presetCategories, "", RECORD_UNTIL_FULL);
+ public TracingConfig(@PredefinedCategories int predefinedCategories,
+ @NonNull List<String> customIncludedCategories,
+ @TracingMode int tracingMode) {
+ mPredefinedCategories = predefinedCategories;
+ mCustomIncludedCategories.addAll(customIncludedCategories);
+ mTracingMode = tracingMode;
}
/**
- * Create a configuration with both preset categories and custom categories.
- * Also allows to specify the tracing mode.
- *
- * Note that the categories are defined by the currently-in-use version of WebView. They live
- * in chromium code and are not part of the Android API. See
- * See <a href="https://www.chromium.org/developers/how-tos/trace-event-profiling-tool">
- * chromium documentation on tracing</a> for more details.
- *
- * <p>
- * Examples:
- *
- * Preset category with a specified trace mode:
- * TracingConfig(CATEGORIES_WEB_DEVELOPER, "", RECORD_UNTIL_FULL_LARGE_BUFFER);
- * Custom categories:
- * TracingConfig(CATEGORIES_NONE, "browser", RECORD_UNTIL_FULL)
- * -- records only the trace events from the "browser" category.
- * TraceConfig(CATEGORIES_NONE, "-input,-gpu", RECORD_UNTIL_FULL)
- * -- records all trace events excluding the events from the "input" and 'gpu' categories.
- * TracingConfig(CATEGORIES_NONE, "blink*,devtools*", RECORD_UNTIL_FULL)
- * -- records only the trace events matching the "blink*" and "devtools*" patterns
- * (e.g. "blink_gc" and "devtools.timeline" categories).
- *
- * Combination of preset and additional custom categories:
- * TracingConfig(CATEGORIES_WEB_DEVELOPER, "memory-infra", RECORD_CONTINUOUSLY)
- * -- records events from the "web developer" categories and events from the "memory-infra"
- * category to understand where memory is being used.
- *
- * @param presetCategories preset categories to use, one of {@link #CATEGORIES_WEB_DEVELOPER},
- * {@link #CATEGORIES_INPUT_LATENCY}, {@link #CATEGORIES_RENDERING},
- * {@link #CATEGORIES_JAVASCRIPT_AND_RENDERING} or
- * {@link #CATEGORIES_FRAME_VIEWER}.
- * @param customCategories a comma-delimited list of category wildcards. A category can
- * have an optional '-' prefix to make it an excluded category.
- * @param tracingMode tracing mode to use, one of {@link #RECORD_UNTIL_FULL},
- * {@link #RECORD_CONTINUOUSLY}, {@link #RECORD_UNTIL_FULL_LARGE_BUFFER}
- * or {@link #RECORD_TO_CONSOLE}.
- */
- public TracingConfig(@PresetCategories int presetCategories,
- @NonNull String customCategories, @TracingMode int tracingMode) {
- mPresetCategories = presetCategories;
- mCustomCategoryPattern = customCategories;
- mTracingMode = RECORD_UNTIL_FULL;
+ * Returns a bitmask of the predefined categories values of this configuration.
+ */
+ @PredefinedCategories
+ public int getPredefinedCategories() {
+ return mPredefinedCategories;
}
/**
- * Returns the custom category pattern for this configuration.
+ * Returns the list of included custom category patterns for this configuration.
*
- * @return empty string if no custom category pattern is specified.
+ * @return empty list if no custom category patterns are specified.
*/
@NonNull
- public String getCustomCategoryPattern() {
- return mCustomCategoryPattern;
- }
-
- /**
- * Returns the preset categories value of this configuration.
- */
- @PresetCategories
- public int getPresetCategories() {
- return mPresetCategories;
+ public List<String> getCustomIncludedCategories() {
+ return mCustomIncludedCategories;
}
/**
@@ -200,4 +154,111 @@ public class TracingConfig {
return mTracingMode;
}
+ /**
+ * Builder used to create {@link TracingConfig} objects.
+ *
+ * Examples:
+ * new TracingConfig.Builder().build()
+ * -- creates a configuration with default options: {@link #CATEGORIES_NONE},
+ * {@link #RECORD_UNTIL_FULL}.
+ * new TracingConfig.Builder().addCategories(CATEGORIES_WEB_DEVELOPER).build()
+ * -- records trace events from the "web developer" predefined category sets.
+ * new TracingConfig.Builder().addCategories(CATEGORIES_RENDERING,
+ * CATEGORIES_INPUT_LATENCY).build()
+ * -- records trace events from the "rendering" and "input latency" predefined
+ * category sets.
+ * new TracingConfig.Builder().addCategories("browser").build()
+ * -- records only the trace events from the "browser" category.
+ * new TracingConfig.Builder().addCategories("blink*","renderer*").build()
+ * -- records only the trace events matching the "blink*" and "renderer*" patterns
+ * (e.g. "blink.animations", "renderer_host" and "renderer.scheduler" categories).
+ * new TracingConfig.Builder().addCategories(CATEGORIES_WEB_DEVELOPER)
+ * .addCategories("disabled-by-default-v8.gc")
+ * .setTracingMode(RECORD_CONTINUOUSLY).build()
+ * -- records events from the "web developer" predefined category set and events from
+ * the "disabled-by-default-v8.gc" category to understand where garbage collection
+ * is being triggered. Uses a ring buffer for internal storage during tracing.
+ */
+ public static class Builder {
+ private @PredefinedCategories int mPredefinedCategories = CATEGORIES_NONE;
+ private final List<String> mCustomIncludedCategories = new ArrayList<String>();
+ private @TracingMode int mTracingMode = RECORD_UNTIL_FULL;
+
+ /**
+ * Default constructor for Builder.
+ */
+ public Builder() {}
+
+ /**
+ * Build {@link TracingConfig} using the current settings.
+ */
+ public TracingConfig build() {
+ return new TracingConfig(mPredefinedCategories, mCustomIncludedCategories,
+ mTracingMode);
+ }
+
+ /**
+ * Adds categories from a predefined set of categories to be included in the trace output.
+ *
+ * @param predefinedCategories list or bitmask of predefined category sets to use:
+ * {@link #CATEGORIES_NONE}, {@link #CATEGORIES_ALL},
+ * {@link #CATEGORIES_WEB_DEVELOPER}, {@link #CATEGORIES_INPUT_LATENCY},
+ * {@link #CATEGORIES_RENDERING},
+ * {@link #CATEGORIES_JAVASCRIPT_AND_RENDERING} or
+ * {@link #CATEGORIES_FRAME_VIEWER}.
+ * @return The builder to facilitate chaining.
+ */
+ public Builder addCategories(@PredefinedCategories int... predefinedCategories) {
+ for (int categorySet : predefinedCategories) {
+ mPredefinedCategories |= categorySet;
+ }
+ return this;
+ }
+
+ /**
+ * Adds custom categories to be included in trace output.
+ *
+ * Note that the categories are defined by the currently-in-use version of WebView. They
+ * live in chromium code and are not part of the Android API. See
+ * See <a href="https://www.chromium.org/developers/how-tos/trace-event-profiling-tool">
+ * chromium documentation on tracing</a> for more details.
+ *
+ * @param categories a list of category patterns. A category pattern can contain wilcards,
+ * e.g. "blink*" or full category name e.g. "renderer.scheduler".
+ * @return The builder to facilitate chaining.
+ */
+ public Builder addCategories(String... categories) {
+ for (String category: categories) {
+ mCustomIncludedCategories.add(category);
+ }
+ return this;
+ }
+
+ /**
+ * Adds custom categories to be included in trace output.
+ *
+ * Same as {@link #addCategories(String...)} but allows to pass a Collection as a parameter.
+ *
+ * @param categories a list of category patters.
+ * @return The builder to facilitate chaining.
+ */
+ public Builder addCategories(Collection<String> categories) {
+ mCustomIncludedCategories.addAll(categories);
+ return this;
+ }
+
+ /**
+ * Sets the tracing mode for this configuration.
+ *
+ * @param tracingMode tracing mode to use, one of {@link #RECORD_UNTIL_FULL},
+ * {@link #RECORD_CONTINUOUSLY} or
+ * {@link #RECORD_UNTIL_FULL_LARGE_BUFFER}.
+ * @return The builder to facilitate chaining.
+ */
+ public Builder setTracingMode(@TracingMode int tracingMode) {
+ mTracingMode = tracingMode;
+ return this;
+ }
+ }
+
}
diff --git a/core/java/android/webkit/TracingController.java b/core/java/android/webkit/TracingController.java
index cadb8a184072..7871021a33c8 100644
--- a/core/java/android/webkit/TracingController.java
+++ b/core/java/android/webkit/TracingController.java
@@ -16,9 +16,12 @@
package android.webkit;
+import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.os.Handler;
+
+import java.io.OutputStream;
+import java.util.concurrent.Executor;
/**
* Manages tracing of WebViews. In particular provides functionality for the app
@@ -29,40 +32,22 @@ import android.os.Handler;
* The resulting trace data is sent back as a byte sequence in json format. This
* file can be loaded in "chrome://tracing" for further analysis.
* <p>
- * Note: All methods in this class must be called on the UI thread. All callbacks
- * are also called on the UI thread.
- * <p>
* Example usage:
* <pre class="prettyprint">
* TracingController tracingController = TracingController.getInstance();
- * tracingController.start(new TraceConfig(CATEGORIES_WEB_DEVELOPER));
+ * tracingController.start(new TraceConfig.Builder()
+ * .addCategories(CATEGORIES_WEB_DEVELOPER).build());
* [..]
- * tracingController.stopAndFlush(new TraceFileOutput("trace.json"), null);
+ * tracingController.stop(new FileOutputStream("trace.json"),
+ * Executors.newSingleThreadExecutor());
* </pre></p>
*/
public abstract class TracingController {
/**
- * Interface for capturing tracing data.
- */
- public interface TracingOutputStream {
- /**
- * Will be called to return tracing data in chunks.
- * Tracing data is returned in json format an array of bytes.
- */
- void write(byte[] chunk);
-
- /**
- * Called when tracing is finished and the data collection is over.
- * There will be no calls to #write after #complete is called.
- */
- void complete();
- }
-
- /**
* Returns the default TracingController instance. At present there is
* only one TracingController instance for all WebView instances,
- * however this restriction may be relaxed in the future.
+ * however this restriction may be relaxed in a future Android release.
*
* @return the default TracingController instance
*/
@@ -72,55 +57,38 @@ public abstract class TracingController {
}
/**
- * Starts tracing all webviews. Depeding on the trace mode in traceConfig
+ * Starts tracing all webviews. Depending on the trace mode in traceConfig
* specifies how the trace events are recorded.
*
* For tracing modes {@link TracingConfig#RECORD_UNTIL_FULL},
* {@link TracingConfig#RECORD_CONTINUOUSLY} and
* {@link TracingConfig#RECORD_UNTIL_FULL_LARGE_BUFFER} the events are recorded
* using an internal buffer and flushed to the outputStream when
- * {@link #stopAndFlush(TracingOutputStream, Handler)} is called.
+ * {@link #stop(OutputStream, Executor)} is called.
*
* @param tracingConfig configuration options to use for tracing
- * @return false if the system is already tracing, true otherwise.
+ * @throws IllegalStateException if the system is already tracing.
*/
- public abstract boolean start(TracingConfig tracingConfig);
+ public abstract void start(@NonNull TracingConfig tracingConfig);
/**
- * Stops tracing and discards all tracing data.
+ * Stops tracing and flushes tracing data to the specified outputStream.
*
- * This method is particularly useful in conjunction with the
- * {@link TracingConfig#RECORD_TO_CONSOLE} tracing mode because tracing data is logged to
- * console and not sent to an outputStream as with
- * {@link #stopAndFlush(TracingOutputStream, Handler)}.
+ * The data is sent to the specified output stream in json format typically
+ * in chunks by invoking {@link java.io.OutputStream#write(byte[])}. On completion
+ * the {@link java.io.OutputStream#close()} method is called.
*
+ * @param outputStream the output steam the tracing data will be sent to. If null
+ * the tracing data will be discarded.
+ * @param executor the {@link java.util.concurrent.Executor} on which the
+ * outputStream #write and #close methods will be invoked.
* @return false if the system was not tracing at the time of the call, true
* otherwise.
*/
- public abstract boolean stop();
-
- /**
- * Stops tracing and flushes tracing data to the specifid outputStream.
- *
- * Note that if the {@link TracingConfig#RECORD_TO_CONSOLE} tracing mode is used
- * nothing will be sent to the outputStream and no TracingOuputStream methods will be
- * called. In that case it is more convenient to just use {@link #stop()} instead.
- *
- * @param outputStream the output steam the tracing data will be sent to.
- * @param handler the {@link android.os.Handler} on which the outputStream callbacks
- * will be invoked. If the handler is null the current thread's Looper
- * will be used.
- * @return false if the system was not tracing at the time of the call, true
- * otherwise.
- */
- public abstract boolean stopAndFlush(TracingOutputStream outputStream,
- @Nullable Handler handler);
+ public abstract boolean stop(@Nullable OutputStream outputStream,
+ @NonNull @CallbackExecutor Executor executor);
/** True if the system is tracing */
public abstract boolean isTracing();
- // TODO: consider adding getTraceBufferUsage, percentage and approx event count.
- // TODO: consider adding String getCategories(), for obtaining the actual list
- // of categories used (given that presets are ints).
-
}
diff --git a/core/java/android/webkit/TracingFileOutputStream.java b/core/java/android/webkit/TracingFileOutputStream.java
deleted file mode 100644
index 8a5fa36c2d99..000000000000
--- a/core/java/android/webkit/TracingFileOutputStream.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.webkit;
-
-import android.annotation.NonNull;
-
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-/**
- * Simple TracingOutputStream implementation which writes the trace data from
- * {@link TracingController} to a new file.
- *
- */
-public class TracingFileOutputStream implements TracingController.TracingOutputStream {
-
- private FileOutputStream mFileOutput;
-
- public TracingFileOutputStream(@NonNull String filename) throws FileNotFoundException {
- mFileOutput = new FileOutputStream(filename);
- }
-
- /**
- * Writes bytes chunk to the file.
- */
- public void write(byte[] chunk) {
- try {
- mFileOutput.write(chunk);
- } catch (IOException e) {
- onIOException(e);
- }
- }
-
- /**
- * Closes the file.
- */
- public void complete() {
- try {
- mFileOutput.close();
- } catch (IOException e) {
- onIOException(e);
- }
- }
-
- private void onIOException(IOException e) {
- throw new RuntimeException(e);
- }
-}
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 7ea1f1edadf5..d32e93c7a862 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -917,7 +917,7 @@ public class LinearLayout extends ViewGroup {
// measurement on any children, we need to measure them now.
int remainingExcess = heightSize - mTotalLength
+ (mAllowInconsistentMeasurement ? 0 : consumedExcessSpace);
- if (skippedMeasure || remainingExcess != 0 && totalWeight > 0.0f) {
+ if (skippedMeasure || totalWeight > 0.0f) {
float remainingWeightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
mTotalLength = 0;
@@ -1300,7 +1300,7 @@ public class LinearLayout extends ViewGroup {
// measurement on any children, we need to measure them now.
int remainingExcess = widthSize - mTotalLength
+ (mAllowInconsistentMeasurement ? 0 : usedExcessSpace);
- if (skippedMeasure || remainingExcess != 0 && totalWeight > 0.0f) {
+ if (skippedMeasure || totalWeight > 0.0f) {
float remainingWeightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
diff --git a/core/java/android/widget/OWNERS b/core/java/android/widget/OWNERS
index 2789bae15923..e4b2930a23cb 100644
--- a/core/java/android/widget/OWNERS
+++ b/core/java/android/widget/OWNERS
@@ -1,9 +1,11 @@
per-file TextView.java = siyamed@google.com
per-file TextView.java = nona@google.com
per-file TextView.java = clarabayarri@google.com
+
per-file EditText.java = siyamed@google.com
per-file EditText.java = nona@google.com
per-file EditText.java = clarabayarri@google.com
+
per-file Editor.java = siyamed@google.com
per-file Editor.java = nona@google.com
per-file Editor.java = clarabayarri@google.com
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index e91db1390582..7217def3cf08 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1583,7 +1583,7 @@ public class PopupWindow {
*
* @hide
*/
- protected final boolean findDropDownPosition(View anchor, WindowManager.LayoutParams outParams,
+ protected boolean findDropDownPosition(View anchor, WindowManager.LayoutParams outParams,
int xOffset, int yOffset, int width, int height, int gravity, boolean allowScroll) {
final int anchorHeight = anchor.getHeight();
final int anchorWidth = anchor.getWidth();
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index 5c4d4d2a7fa0..c98714799742 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -183,13 +183,17 @@ public class RadioGroup extends LinearLayout {
}
private void setCheckedId(@IdRes int id) {
+ boolean changed = id != mCheckedId;
mCheckedId = id;
+
if (mOnCheckedChangeListener != null) {
mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId);
}
- final AutofillManager afm = mContext.getSystemService(AutofillManager.class);
- if (afm != null) {
- afm.notifyValueChanged(this);
+ if (changed) {
+ final AutofillManager afm = mContext.getSystemService(AutofillManager.class);
+ if (afm != null) {
+ afm.notifyValueChanged(this);
+ }
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5710db3ce8e0..1e02c3062d97 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -791,11 +791,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// mAutoSizeStepGranularityInPx.
private boolean mHasPresetAutoSizeValues = false;
+ // Autofill-related attributes
+ //
// Indicates whether the text was set statically or dynamically, so it can be used to
// sanitize autofill requests.
private boolean mTextSetFromXmlOrResourceId = false;
- // Resource id used to set the text - used for autofill purposes.
+ // Resource id used to set the text.
private @StringRes int mTextId = ResourceId.ID_NULL;
+ // Last value used on AFM.notifyValueChanged(), used to optimize autofill workflow by avoiding
+ // calls when the value did not change
+ private CharSequence mLastValueSentToAutofillManager;
+ //
+ // End of autofill-related attributes
/**
* Kick-start the font cache for the zygote process (to pay the cost of
@@ -5665,7 +5672,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (needEditableForNotification) {
sendAfterTextChanged((Editable) text);
} else {
- // Always notify AutoFillManager - it will return right away if autofill is disabled.
notifyAutoFillManagerAfterTextChangedIfNeeded();
}
@@ -9697,11 +9703,21 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return;
}
final AutofillManager afm = mContext.getSystemService(AutofillManager.class);
- if (afm != null) {
+ if (afm == null) {
+ return;
+ }
+
+ if (mLastValueSentToAutofillManager == null
+ || !mLastValueSentToAutofillManager.equals(mText)) {
if (android.view.autofill.Helper.sVerbose) {
- Log.v(LOG_TAG, "sendAfterTextChanged(): notify AFM for text=" + mText);
+ Log.v(LOG_TAG, "notifying AFM after text changed");
}
afm.notifyValueChanged(TextView.this);
+ mLastValueSentToAutofillManager = mText;
+ } else {
+ if (android.view.autofill.Helper.sVerbose) {
+ Log.v(LOG_TAG, "not notifying AFM on unchanged text");
+ }
}
}
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index 6bd693061a85..61aeca679303 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -56,9 +56,6 @@ public class ResolverListController {
private static final String TAG = "ResolverListController";
private static final boolean DEBUG = false;
- Object mLock = new Object();
-
- @GuardedBy("mLock")
private ResolverComparator mResolverComparator;
private boolean isComputed = false;
@@ -73,10 +70,8 @@ public class ResolverListController {
mLaunchedFromUid = launchedFromUid;
mTargetIntent = targetIntent;
mReferrerPackage = referrerPackage;
- synchronized (mLock) {
- mResolverComparator =
- new ResolverComparator(mContext, mTargetIntent, mReferrerPackage, null);
- }
+ mResolverComparator =
+ new ResolverComparator(mContext, mTargetIntent, mReferrerPackage, null);
}
@VisibleForTesting
@@ -244,29 +239,27 @@ public class ResolverListController {
@VisibleForTesting
@WorkerThread
public void sort(List<ResolverActivity.ResolvedComponentInfo> inputList) {
- synchronized (mLock) {
- if (mResolverComparator == null) {
- Log.d(TAG, "Comparator has already been destroyed; skipped.");
- return;
+ if (mResolverComparator == null) {
+ Log.d(TAG, "Comparator has already been destroyed; skipped.");
+ return;
+ }
+ try {
+ long beforeRank = System.currentTimeMillis();
+ if (!isComputed) {
+ final CountDownLatch finishComputeSignal = new CountDownLatch(1);
+ ComputeCallback callback = new ComputeCallback(finishComputeSignal);
+ mResolverComparator.setCallBack(callback);
+ mResolverComparator.compute(inputList);
+ finishComputeSignal.await();
+ isComputed = true;
}
- final CountDownLatch finishComputeSignal = new CountDownLatch(1);
- ComputeCallback callback = new ComputeCallback(finishComputeSignal);
- mResolverComparator.setCallBack(callback);
- try {
- long beforeRank = System.currentTimeMillis();
- if (!isComputed) {
- mResolverComparator.compute(inputList);
- finishComputeSignal.await();
- isComputed = true;
- }
- Collections.sort(inputList, mResolverComparator);
- long afterRank = System.currentTimeMillis();
- if (DEBUG) {
- Log.d(TAG, "Time Cost: " + Long.toString(afterRank - beforeRank));
- }
- } catch (InterruptedException e) {
- Log.e(TAG, "Compute & Sort was interrupted: " + e);
+ Collections.sort(inputList, mResolverComparator);
+ long afterRank = System.currentTimeMillis();
+ if (DEBUG) {
+ Log.d(TAG, "Time Cost: " + Long.toString(afterRank - beforeRank));
}
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Compute & Sort was interrupted: " + e);
}
}
@@ -287,36 +280,18 @@ public class ResolverListController {
@VisibleForTesting
public float getScore(ResolverActivity.DisplayResolveInfo target) {
- synchronized (mLock) {
- if (mResolverComparator == null) {
- return 0.0f;
- }
- return mResolverComparator.getScore(target.getResolvedComponentName());
- }
+ return mResolverComparator.getScore(target.getResolvedComponentName());
}
public void updateModel(ComponentName componentName) {
- synchronized (mLock) {
- if (mResolverComparator != null) {
- mResolverComparator.updateModel(componentName);
- }
- }
+ mResolverComparator.updateModel(componentName);
}
public void updateChooserCounts(String packageName, int userId, String action) {
- synchronized (mLock) {
- if (mResolverComparator != null) {
- mResolverComparator.updateChooserCounts(packageName, userId, action);
- }
- }
+ mResolverComparator.updateChooserCounts(packageName, userId, action);
}
public void destroy() {
- synchronized (mLock) {
- if (mResolverComparator != null) {
- mResolverComparator.destroy();
- }
- mResolverComparator = null;
- }
+ mResolverComparator.destroy();
}
}
diff --git a/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java b/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java
index 500c028ed4c6..bf151c39271a 100644
--- a/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java
+++ b/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java
@@ -57,6 +57,8 @@ public class GradientDrawable extends Drawable {
private int mMainColor;
private int mSecondaryColor;
private ValueAnimator mColorAnimation;
+ private int mMainColorTo;
+ private int mSecondaryColorTo;
public GradientDrawable(@NonNull Context context) {
mDensity = context.getResources().getDisplayMetrics().density;
@@ -76,7 +78,7 @@ public class GradientDrawable extends Drawable {
}
public void setColors(int mainColor, int secondaryColor, boolean animated) {
- if (mainColor == mMainColor && secondaryColor == mSecondaryColor) {
+ if (mainColor == mMainColorTo && secondaryColor == mSecondaryColorTo) {
return;
}
@@ -84,6 +86,9 @@ public class GradientDrawable extends Drawable {
mColorAnimation.cancel();
}
+ mMainColorTo = mainColor;
+ mSecondaryColorTo = mainColor;
+
if (animated) {
final int mainFrom = mMainColor;
final int secFrom = mSecondaryColor;
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
index 4a181b27b2e3..44adbb22eb7e 100644
--- a/core/java/com/android/internal/notification/SystemNotificationChannels.java
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -49,6 +49,7 @@ public class SystemNotificationChannels {
public static String USB = "USB";
public static String FOREGROUND_SERVICE = "FOREGROUND_SERVICE";
public static String HEAVY_WEIGHT_APP = "HEAVY_WEIGHT_APP";
+ public static String SYSTEM_CHANGES = "SYSTEM_CHANGES";
public static void createAll(Context context) {
final NotificationManager nm = context.getSystemService(NotificationManager.class);
@@ -152,6 +153,11 @@ public class SystemNotificationChannels {
.build());
channelsList.add(heavyWeightChannel);
+ NotificationChannel systemChanges = new NotificationChannel(SYSTEM_CHANGES,
+ context.getString(R.string.notification_channel_system_changes),
+ NotificationManager.IMPORTANCE_LOW);
+ channelsList.add(systemChanges);
+
nm.createNotificationChannels(channelsList);
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index eb58b0919385..4e515918a0cd 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -187,7 +187,7 @@ public class BatteryStatsImpl extends BatteryStats {
public final AtomicFile mCheckinFile;
public final AtomicFile mDailyFile;
- static final int MSG_UPDATE_WAKELOCKS = 1;
+ static final int MSG_REPORT_CPU_UPDATE_NEEDED = 1;
static final int MSG_REPORT_POWER_CHANGE = 2;
static final int MSG_REPORT_CHARGING = 3;
static final long DELAY_UPDATE_WAKELOCKS = 5*1000;
@@ -230,6 +230,13 @@ public class BatteryStatsImpl extends BatteryStats {
@VisibleForTesting
protected final SparseIntArray mPendingUids = new SparseIntArray();
+ @GuardedBy("this")
+ private long mNumCpuTimeReads;
+ @GuardedBy("this")
+ private long mNumBatchedCpuTimeReads;
+ @GuardedBy("this")
+ private long mCpuTimeReadsTrackingStartTime = SystemClock.uptimeMillis();
+
/** Container for Resource Power Manager stats. Updated by updateRpmStatsLocked. */
private final RpmStats mTmpRpmStats = new RpmStats();
/** The soonest the RPM stats can be updated after it was last updated. */
@@ -273,10 +280,7 @@ public class BatteryStatsImpl extends BatteryStats {
public void handleMessage(Message msg) {
BatteryCallback cb = mCallback;
switch (msg.what) {
- case MSG_UPDATE_WAKELOCKS:
- synchronized (BatteryStatsImpl.this) {
- updateCpuTimeLocked();
- }
+ case MSG_REPORT_CPU_UPDATE_NEEDED:
if (cb != null) {
cb.batteryNeedsCpuUpdate();
}
@@ -302,6 +306,10 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
+ public void postBatteryNeedsCpuUpdateMsg() {
+ mHandler.sendEmptyMessage(MSG_REPORT_CPU_UPDATE_NEEDED);
+ }
+
/**
* Update per-freq cpu times for all the uids in {@link #mPendingUids}.
*/
@@ -484,9 +492,14 @@ public class BatteryStatsImpl extends BatteryStats {
Future<?> scheduleSync(String reason, int flags);
Future<?> scheduleCpuSyncDueToRemovedUid(int uid);
- Future<?> scheduleReadProcStateCpuTimes(boolean onBattery, boolean onBatteryScreenOff);
+ Future<?> scheduleReadProcStateCpuTimes(boolean onBattery, boolean onBatteryScreenOff,
+ long delayMillis);
Future<?> scheduleCopyFromAllUidsCpuTimes(boolean onBattery, boolean onBatteryScreenOff);
Future<?> scheduleCpuSyncDueToSettingChange();
+ Future<?> scheduleCpuSyncDueToScreenStateChange(boolean onBattery,
+ boolean onBatteryScreenOff);
+ Future<?> scheduleCpuSyncDueToWakelockChange(long delayMillis);
+ void cancelCpuSyncDueToWakelockChange();
}
public Handler mHandler;
@@ -1453,12 +1466,10 @@ public class BatteryStatsImpl extends BatteryStats {
long mCount;
long mLoadedCount;
long mUnpluggedCount;
- long mPluggedCount;
LongSamplingCounter(TimeBase timeBase, Parcel in) {
mTimeBase = timeBase;
- mPluggedCount = in.readLong();
- mCount = mPluggedCount;
+ mCount = in.readLong();
mLoadedCount = in.readLong();
mUnpluggedCount = in.readLong();
timeBase.add(this);
@@ -1477,16 +1488,15 @@ public class BatteryStatsImpl extends BatteryStats {
@Override
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
- mUnpluggedCount = mPluggedCount;
+ mUnpluggedCount = mCount;
}
@Override
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
- mPluggedCount = mCount;
}
public long getCountLocked(int which) {
- long val = mTimeBase.isRunning() ? mCount : mPluggedCount;
+ long val = mCount;
if (which == STATS_SINCE_UNPLUGGED) {
val -= mUnpluggedCount;
} else if (which != STATS_SINCE_CHARGED) {
@@ -1499,12 +1509,15 @@ public class BatteryStatsImpl extends BatteryStats {
public void logState(Printer pw, String prefix) {
pw.println(prefix + "mCount=" + mCount
+ " mLoadedCount=" + mLoadedCount
- + " mUnpluggedCount=" + mUnpluggedCount
- + " mPluggedCount=" + mPluggedCount);
+ + " mUnpluggedCount=" + mUnpluggedCount);
}
void addCountLocked(long count) {
- if (mTimeBase.isRunning()) {
+ addCountLocked(count, mTimeBase.isRunning());
+ }
+
+ void addCountLocked(long count, boolean isRunning) {
+ if (isRunning) {
mCount += count;
}
}
@@ -1514,7 +1527,7 @@ public class BatteryStatsImpl extends BatteryStats {
*/
void reset(boolean detachIfReset) {
mCount = 0;
- mLoadedCount = mPluggedCount = mUnpluggedCount = 0;
+ mLoadedCount = mUnpluggedCount = 0;
if (detachIfReset) {
detach();
}
@@ -1531,7 +1544,7 @@ public class BatteryStatsImpl extends BatteryStats {
void readSummaryFromParcelLocked(Parcel in) {
mLoadedCount = in.readLong();
mCount = mLoadedCount;
- mUnpluggedCount = mPluggedCount = mLoadedCount;
+ mUnpluggedCount = mLoadedCount;
}
}
@@ -3852,9 +3865,6 @@ public class BatteryStatsImpl extends BatteryStats {
+ Display.stateToString(screenState)
+ " and battery is " + (unplugged ? "on" : "off"));
}
- updateCpuTimeLocked();
- mExternalSync.scheduleCopyFromAllUidsCpuTimes(mOnBatteryTimeBase.isRunning(),
- mOnBatteryScreenOffTimeBase.isRunning());
mOnBatteryTimeBase.setRunning(unplugged, uptime, realtime);
if (updateOnBatteryTimeBase) {
@@ -4143,15 +4153,11 @@ public class BatteryStatsImpl extends BatteryStats {
}
private void requestWakelockCpuUpdate() {
- if (!mHandler.hasMessages(MSG_UPDATE_WAKELOCKS)) {
- Message m = mHandler.obtainMessage(MSG_UPDATE_WAKELOCKS);
- mHandler.sendMessageDelayed(m, DELAY_UPDATE_WAKELOCKS);
- }
+ mExternalSync.scheduleCpuSyncDueToWakelockChange(DELAY_UPDATE_WAKELOCKS);
}
private void requestImmediateCpuUpdate() {
- mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
- mHandler.sendEmptyMessage(MSG_UPDATE_WAKELOCKS);
+ mExternalSync.scheduleCpuSyncDueToWakelockChange(0 /* delayMillis */);
}
public void setRecordAllHistoryLocked(boolean enabled) {
@@ -4554,7 +4560,7 @@ public class BatteryStatsImpl extends BatteryStats {
}
public boolean startAddingCpuLocked() {
- mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
+ mExternalSync.cancelCpuSyncDueToWakelockChange();
return mOnBatteryInternal;
}
@@ -4807,6 +4813,8 @@ public class BatteryStatsImpl extends BatteryStats {
+ Display.stateToString(state));
addHistoryRecordLocked(elapsedRealtime, uptime);
}
+ mExternalSync.scheduleCpuSyncDueToScreenStateChange(
+ mOnBatteryTimeBase.isRunning(), mOnBatteryScreenOffTimeBase.isRunning());
if (isScreenOn(state)) {
updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), state,
mClocks.uptimeMillis() * 1000, elapsedRealtime * 1000);
@@ -5286,6 +5294,18 @@ public class BatteryStatsImpl extends BatteryStats {
case TelephonyManager.NETWORK_TYPE_HSPAP:
bin = DATA_CONNECTION_HSPAP;
break;
+ case TelephonyManager.NETWORK_TYPE_GSM:
+ bin = DATA_CONNECTION_GSM;
+ break;
+ case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
+ bin = DATA_CONNECTION_TD_SCDMA;
+ break;
+ case TelephonyManager.NETWORK_TYPE_IWLAN:
+ bin = DATA_CONNECTION_IWLAN;
+ break;
+ case TelephonyManager.NETWORK_TYPE_LTE_CA:
+ bin = DATA_CONNECTION_LTE_CA;
+ break;
default:
bin = DATA_CONNECTION_OTHER;
break;
@@ -9196,8 +9216,14 @@ public class BatteryStatsImpl extends BatteryStats {
}
public void addCpuTimeLocked(int utime, int stime) {
- mUserTime += utime;
- mSystemTime += stime;
+ addCpuTimeLocked(utime, stime, mBsi.mOnBatteryTimeBase.isRunning());
+ }
+
+ public void addCpuTimeLocked(int utime, int stime, boolean isRunning) {
+ if (isRunning) {
+ mUserTime += utime;
+ mSystemTime += stime;
+ }
}
public void addForegroundTimeLocked(long ttime) {
@@ -9676,7 +9702,11 @@ public class BatteryStatsImpl extends BatteryStats {
if (mBsi.mPendingUids.size() == 0) {
mBsi.mExternalSync.scheduleReadProcStateCpuTimes(
mBsi.mOnBatteryTimeBase.isRunning(),
- mBsi.mOnBatteryScreenOffTimeBase.isRunning());
+ mBsi.mOnBatteryScreenOffTimeBase.isRunning(),
+ mBsi.mConstants.PROC_STATE_CPU_TIMES_READ_DELAY_MS);
+ mBsi.mNumCpuTimeReads++;
+ } else {
+ mBsi.mNumBatchedCpuTimeReads++;
}
if (mBsi.mPendingUids.indexOfKey(mUid) < 0
|| ArrayUtils.contains(CRITICAL_PROC_STATES, mProcessState)) {
@@ -11210,6 +11240,25 @@ public class BatteryStatsImpl extends BatteryStats {
private ModemActivityInfo mLastModemActivityInfo =
new ModemActivityInfo(0, 0, 0, new int[0], 0, 0);
+ private ModemActivityInfo getDeltaModemActivityInfo(ModemActivityInfo activityInfo) {
+ if (activityInfo == null) {
+ return null;
+ }
+ int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
+ for (int i = 0; i < ModemActivityInfo.TX_POWER_LEVELS; i++) {
+ txTimeMs[i] = activityInfo.getTxTimeMillis()[i]
+ - mLastModemActivityInfo.getTxTimeMillis()[i];
+ }
+ ModemActivityInfo deltaInfo = new ModemActivityInfo(activityInfo.getTimestamp(),
+ activityInfo.getSleepTimeMillis() - mLastModemActivityInfo.getSleepTimeMillis(),
+ activityInfo.getIdleTimeMillis() - mLastModemActivityInfo.getIdleTimeMillis(),
+ txTimeMs,
+ activityInfo.getRxTimeMillis() - mLastModemActivityInfo.getRxTimeMillis(),
+ activityInfo.getEnergyUsed() - mLastModemActivityInfo.getEnergyUsed());
+ mLastModemActivityInfo = activityInfo;
+ return deltaInfo;
+ }
+
/**
* Distribute Cell radio energy info and network traffic to apps.
*/
@@ -11217,9 +11266,10 @@ public class BatteryStatsImpl extends BatteryStats {
if (DEBUG_ENERGY) {
Slog.d(TAG, "Updating mobile radio stats with " + activityInfo);
}
+ ModemActivityInfo deltaInfo = getDeltaModemActivityInfo(activityInfo);
// Add modem tx power to history.
- addModemTxPowerToHistory(activityInfo);
+ addModemTxPowerToHistory(deltaInfo);
// Grab a separate lock to acquire the network stats, which may do I/O.
NetworkStats delta = null;
@@ -11233,22 +11283,6 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
- int rxTimeMs = 0;
- int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
- int idleTimeMs = 0;
- int sleepTimeMs = 0;
- if (activityInfo != null) {
- rxTimeMs = activityInfo.getRxTimeMillis() - mLastModemActivityInfo.getRxTimeMillis();
- for (int i = 0; i < ModemActivityInfo.TX_POWER_LEVELS; i++) {
- txTimeMs[i] = activityInfo.getTxTimeMillis()[i]
- - mLastModemActivityInfo.getTxTimeMillis()[i];
- }
- idleTimeMs =
- activityInfo.getIdleTimeMillis() - mLastModemActivityInfo.getIdleTimeMillis();
- sleepTimeMs =
- activityInfo.getSleepTimeMillis() - mLastModemActivityInfo.getSleepTimeMillis();
- }
-
synchronized (this) {
if (!mOnBatteryInternal) {
if (delta != null) {
@@ -11257,14 +11291,14 @@ public class BatteryStatsImpl extends BatteryStats {
return;
}
- if (activityInfo != null) {
+ if (deltaInfo != null) {
mHasModemReporting = true;
mModemActivity.getIdleTimeCounter().addCountLocked(
- idleTimeMs);
- mModemActivity.getRxTimeCounter().addCountLocked(rxTimeMs);
+ deltaInfo.getIdleTimeMillis());
+ mModemActivity.getRxTimeCounter().addCountLocked(deltaInfo.getRxTimeMillis());
for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
mModemActivity.getTxTimeCounters()[lvl]
- .addCountLocked(txTimeMs[lvl]);
+ .addCountLocked(deltaInfo.getTxTimeMillis()[lvl]);
}
// POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
@@ -11272,16 +11306,17 @@ public class BatteryStatsImpl extends BatteryStats {
PowerProfile.POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
if (opVolt != 0) {
double energyUsed =
- sleepTimeMs *
+ deltaInfo.getSleepTimeMillis() *
mPowerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_SLEEP)
- + idleTimeMs *
+ + deltaInfo.getIdleTimeMillis() *
mPowerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_IDLE)
- + rxTimeMs *
+ + deltaInfo.getRxTimeMillis() *
mPowerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX);
+ int[] txTimeMs = deltaInfo.getTxTimeMillis();
for (int i = 0; i < Math.min(txTimeMs.length,
- SignalStrength.NUM_SIGNAL_STRENGTH_BINS); i++) {
+ SignalStrength.NUM_SIGNAL_STRENGTH_BINS); i++) {
energyUsed += txTimeMs[i] * mPowerProfile.getAveragePower(
- PowerProfile.POWER_MODEM_CONTROLLER_TX, i);
+ PowerProfile.POWER_MODEM_CONTROLLER_TX, i);
}
// We store the power drain as mAms.
@@ -11357,11 +11392,11 @@ public class BatteryStatsImpl extends BatteryStats {
radioTime -= appRadioTime;
totalPackets -= appPackets;
- if (activityInfo != null) {
+ if (deltaInfo != null) {
ControllerActivityCounterImpl activityCounter =
u.getOrCreateModemControllerActivityLocked();
if (totalRxPackets > 0 && entry.rxPackets > 0) {
- final long rxMs = (entry.rxPackets * rxTimeMs)
+ final long rxMs = (entry.rxPackets * deltaInfo.getRxTimeMillis())
/ totalRxPackets;
activityCounter.getRxTimeCounter().addCountLocked(rxMs);
}
@@ -11369,7 +11404,7 @@ public class BatteryStatsImpl extends BatteryStats {
if (totalTxPackets > 0 && entry.txPackets > 0) {
for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
long txMs =
- entry.txPackets * txTimeMs[lvl];
+ entry.txPackets * deltaInfo.getTxTimeMillis()[lvl];
txMs /= totalTxPackets;
activityCounter.getTxTimeCounters()[lvl].addCountLocked(txMs);
}
@@ -11761,13 +11796,24 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
+ public boolean isOnBatteryLocked() {
+ return mOnBatteryTimeBase.isRunning();
+ }
+
+ public boolean isOnBatteryScreenOffLocked() {
+ return mOnBatteryScreenOffTimeBase.isRunning();
+ }
+
/**
* Read and distribute CPU usage across apps. If their are partial wakelocks being held
* and we are on battery with screen off, we give more of the cpu time to those apps holding
* wakelocks. If the screen is on, we just assign the actual cpu time an app used.
+ * It's possible this will be invoked after the internal battery/screen states are updated, so
+ * passing the appropriate battery/screen states to try attribute the cpu times to correct
+ * buckets.
*/
@GuardedBy("this")
- public void updateCpuTimeLocked() {
+ public void updateCpuTimeLocked(boolean onBattery, boolean onBatteryScreenOff) {
if (mPowerProfile == null) {
return;
}
@@ -11784,7 +11830,7 @@ public class BatteryStatsImpl extends BatteryStats {
// usually holding the wakelock on behalf of an app.
// And Only distribute cpu power to wakelocks if the screen is off and we're on battery.
ArrayList<StopwatchTimer> partialTimersToConsider = null;
- if (mOnBatteryScreenOffTimeBase.isRunning()) {
+ if (onBatteryScreenOff) {
partialTimersToConsider = new ArrayList<>();
for (int i = mPartialTimers.size() - 1; i >= 0; --i) {
final StopwatchTimer timer = mPartialTimers.get(i);
@@ -11802,7 +11848,7 @@ public class BatteryStatsImpl extends BatteryStats {
// When the battery is not on, we don't attribute the cpu times to any timers but we still
// need to take the snapshots.
- if (!mOnBatteryInternal) {
+ if (!onBattery) {
mKernelUidCpuTimeReader.readDelta(null);
mKernelUidCpuFreqTimeReader.readDelta(null);
if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
@@ -11818,16 +11864,16 @@ public class BatteryStatsImpl extends BatteryStats {
mUserInfoProvider.refreshUserIds();
final SparseLongArray updatedUids = mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()
? null : new SparseLongArray();
- readKernelUidCpuTimesLocked(partialTimersToConsider, updatedUids);
+ readKernelUidCpuTimesLocked(partialTimersToConsider, updatedUids, onBattery);
// updatedUids=null means /proc/uid_time_in_state provides snapshots of per-cluster cpu
// freqs, so no need to approximate these values.
if (updatedUids != null) {
- updateClusterSpeedTimes(updatedUids);
+ updateClusterSpeedTimes(updatedUids, onBattery);
}
- readKernelUidCpuFreqTimesLocked(partialTimersToConsider);
+ readKernelUidCpuFreqTimesLocked(partialTimersToConsider, onBattery, onBatteryScreenOff);
if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
- readKernelUidCpuActiveTimesLocked();
- readKernelUidCpuClusterTimesLocked();
+ readKernelUidCpuActiveTimesLocked(onBattery);
+ readKernelUidCpuClusterTimesLocked(onBattery);
}
}
@@ -11867,7 +11913,7 @@ public class BatteryStatsImpl extends BatteryStats {
* @param updatedUids The uids for which times spent at different frequencies are calculated.
*/
@VisibleForTesting
- public void updateClusterSpeedTimes(@NonNull SparseLongArray updatedUids) {
+ public void updateClusterSpeedTimes(@NonNull SparseLongArray updatedUids, boolean onBattery) {
long totalCpuClustersTimeMs = 0;
// Read the time spent for each cluster at various cpu frequencies.
final long[][] clusterSpeedTimesMs = new long[mKernelCpuSpeedReaders.length][];
@@ -11909,7 +11955,7 @@ public class BatteryStatsImpl extends BatteryStats {
}
cpuSpeeds[speed].addCountLocked(appCpuTimeUs
* clusterSpeedTimesMs[cluster][speed]
- / totalCpuClustersTimeMs);
+ / totalCpuClustersTimeMs, onBattery);
}
}
}
@@ -11926,7 +11972,7 @@ public class BatteryStatsImpl extends BatteryStats {
*/
@VisibleForTesting
public void readKernelUidCpuTimesLocked(@Nullable ArrayList<StopwatchTimer> partialTimers,
- @Nullable SparseLongArray updatedUids) {
+ @Nullable SparseLongArray updatedUids, boolean onBattery) {
mTempTotalCpuUserTimeUs = mTempTotalCpuSystemTimeUs = 0;
final int numWakelocks = partialTimers == null ? 0 : partialTimers.size();
final long startTimeMs = mClocks.uptimeMillis();
@@ -11977,8 +12023,8 @@ public class BatteryStatsImpl extends BatteryStats {
Slog.d(TAG, sb.toString());
}
- u.mUserCpuTime.addCountLocked(userTimeUs);
- u.mSystemCpuTime.addCountLocked(systemTimeUs);
+ u.mUserCpuTime.addCountLocked(userTimeUs, onBattery);
+ u.mSystemCpuTime.addCountLocked(systemTimeUs, onBattery);
if (updatedUids != null) {
updatedUids.put(u.getUid(), userTimeUs + systemTimeUs);
}
@@ -12010,15 +12056,15 @@ public class BatteryStatsImpl extends BatteryStats {
Slog.d(TAG, sb.toString());
}
- timer.mUid.mUserCpuTime.addCountLocked(userTimeUs);
- timer.mUid.mSystemCpuTime.addCountLocked(systemTimeUs);
+ timer.mUid.mUserCpuTime.addCountLocked(userTimeUs, onBattery);
+ timer.mUid.mSystemCpuTime.addCountLocked(systemTimeUs, onBattery);
if (updatedUids != null) {
final int uid = timer.mUid.getUid();
updatedUids.put(uid, updatedUids.get(uid, 0) + userTimeUs + systemTimeUs);
}
final Uid.Proc proc = timer.mUid.getProcessStatsLocked("*wakelock*");
- proc.addCpuTimeLocked(userTimeUs / 1000, systemTimeUs / 1000);
+ proc.addCpuTimeLocked(userTimeUs / 1000, systemTimeUs / 1000, onBattery);
mTempTotalCpuUserTimeUs -= userTimeUs;
mTempTotalCpuSystemTimeUs -= systemTimeUs;
@@ -12033,7 +12079,8 @@ public class BatteryStatsImpl extends BatteryStats {
* @param partialTimers The wakelock holders among which the cpu freq times will be distributed.
*/
@VisibleForTesting
- public void readKernelUidCpuFreqTimesLocked(@Nullable ArrayList<StopwatchTimer> partialTimers) {
+ public void readKernelUidCpuFreqTimesLocked(@Nullable ArrayList<StopwatchTimer> partialTimers,
+ boolean onBattery, boolean onBatteryScreenOff) {
final boolean perClusterTimesAvailable =
mKernelUidCpuFreqTimeReader.perClusterTimesAvailable();
final int numWakelocks = partialTimers == null ? 0 : partialTimers.size();
@@ -12056,13 +12103,13 @@ public class BatteryStatsImpl extends BatteryStats {
if (u.mCpuFreqTimeMs == null || u.mCpuFreqTimeMs.getSize() != cpuFreqTimeMs.length) {
u.mCpuFreqTimeMs = new LongSamplingCounterArray(mOnBatteryTimeBase);
}
- u.mCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs);
+ u.mCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs, onBattery);
if (u.mScreenOffCpuFreqTimeMs == null ||
u.mScreenOffCpuFreqTimeMs.getSize() != cpuFreqTimeMs.length) {
u.mScreenOffCpuFreqTimeMs = new LongSamplingCounterArray(
mOnBatteryScreenOffTimeBase);
}
- u.mScreenOffCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs);
+ u.mScreenOffCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs, onBatteryScreenOff);
if (perClusterTimesAvailable) {
if (u.mCpuClusterSpeedTimesUs == null ||
@@ -12098,7 +12145,7 @@ public class BatteryStatsImpl extends BatteryStats {
} else {
appAllocationUs = cpuFreqTimeMs[freqIndex] * 1000;
}
- cpuTimesUs[speed].addCountLocked(appAllocationUs);
+ cpuTimesUs[speed].addCountLocked(appAllocationUs, onBattery);
freqIndex++;
}
}
@@ -12132,7 +12179,7 @@ public class BatteryStatsImpl extends BatteryStats {
}
final long allocationUs =
mWakeLockAllocationsUs[cluster][speed] / (numWakelocks - i);
- cpuTimeUs[speed].addCountLocked(allocationUs);
+ cpuTimeUs[speed].addCountLocked(allocationUs, onBattery);
mWakeLockAllocationsUs[cluster][speed] -= allocationUs;
}
}
@@ -12145,7 +12192,7 @@ public class BatteryStatsImpl extends BatteryStats {
* counters.
*/
@VisibleForTesting
- public void readKernelUidCpuActiveTimesLocked() {
+ public void readKernelUidCpuActiveTimesLocked(boolean onBattery) {
final long startTimeMs = mClocks.uptimeMillis();
mKernelUidCpuActiveTimeReader.readDelta((uid, cpuActiveTimesUs) -> {
uid = mapUid(uid);
@@ -12160,7 +12207,7 @@ public class BatteryStatsImpl extends BatteryStats {
return;
}
final Uid u = getUidStatsLocked(uid);
- u.mCpuActiveTimeMs.addCountLocked(cpuActiveTimesUs);
+ u.mCpuActiveTimeMs.addCountLocked(cpuActiveTimesUs, onBattery);
});
final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
@@ -12174,7 +12221,7 @@ public class BatteryStatsImpl extends BatteryStats {
* counters.
*/
@VisibleForTesting
- public void readKernelUidCpuClusterTimesLocked() {
+ public void readKernelUidCpuClusterTimesLocked(boolean onBattery) {
final long startTimeMs = mClocks.uptimeMillis();
mKernelUidCpuClusterTimeReader.readDelta((uid, cpuClusterTimesUs) -> {
uid = mapUid(uid);
@@ -12189,7 +12236,7 @@ public class BatteryStatsImpl extends BatteryStats {
return;
}
final Uid u = getUidStatsLocked(uid);
- u.mCpuClusterTimesMs.addCountLocked(cpuClusterTimesUs);
+ u.mCpuClusterTimesMs.addCountLocked(cpuClusterTimesUs, onBattery);
});
final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
@@ -12399,9 +12446,7 @@ public class BatteryStatsImpl extends BatteryStats {
reportChangesToStatsLog(mHaveBatteryLevel ? mHistoryCur : null,
status, plugType, level, temp);
- final boolean onBattery =
- plugType == BATTERY_PLUGGED_NONE &&
- status != BatteryManager.BATTERY_STATUS_UNKNOWN;
+ final boolean onBattery = isOnBattery(plugType, status);
final long uptime = mClocks.uptimeMillis();
final long elapsedRealtime = mClocks.elapsedRealtime();
if (!mHaveBatteryLevel) {
@@ -12591,6 +12636,10 @@ public class BatteryStatsImpl extends BatteryStats {
mMaxLearnedBatteryCapacity = Math.max(mMaxLearnedBatteryCapacity, chargeFullUAh);
}
+ public static boolean isOnBattery(int plugType, int status) {
+ return plugType == BATTERY_PLUGGED_NONE && status != BatteryManager.BATTERY_STATUS_UNKNOWN;
+ }
+
// Inform StatsLog of setBatteryState changes.
// If this is the first reporting, pass in recentPast == null.
private void reportChangesToStatsLog(HistoryItem recentPast,
@@ -13135,15 +13184,19 @@ public class BatteryStatsImpl extends BatteryStats {
= "track_cpu_active_cluster_time";
public static final String KEY_READ_BINARY_CPU_TIME
= "read_binary_cpu_time";
+ public static final String KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS
+ = "proc_state_cpu_times_read_delay_ms";
private static final boolean DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE = true;
private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true;
private static final boolean DEFAULT_READ_BINARY_CPU_TIME = false;
+ private static final long DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS = 5_000;
public boolean TRACK_CPU_TIMES_BY_PROC_STATE = DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE;
public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME;
// Not used right now.
public boolean READ_BINARY_CPU_TIME = DEFAULT_READ_BINARY_CPU_TIME;
+ public long PROC_STATE_CPU_TIMES_READ_DELAY_MS = DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -13183,7 +13236,9 @@ public class BatteryStatsImpl extends BatteryStats {
KEY_TRACK_CPU_ACTIVE_CLUSTER_TIME, DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME);
READ_BINARY_CPU_TIME = mParser.getBoolean(
KEY_READ_BINARY_CPU_TIME, DEFAULT_READ_BINARY_CPU_TIME);
-
+ updateProcStateCpuTimesReadDelayMs(PROC_STATE_CPU_TIMES_READ_DELAY_MS,
+ mParser.getLong(KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS,
+ DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS));
}
}
@@ -13192,6 +13247,19 @@ public class BatteryStatsImpl extends BatteryStats {
if (isEnabled && !wasEnabled) {
mKernelSingleUidTimeReader.markDataAsStale(true);
mExternalSync.scheduleCpuSyncDueToSettingChange();
+
+ mNumCpuTimeReads = 0;
+ mNumBatchedCpuTimeReads = 0;
+ mCpuTimeReadsTrackingStartTime = mClocks.uptimeMillis();
+ }
+ }
+
+ private void updateProcStateCpuTimesReadDelayMs(long oldDelayMillis, long newDelayMillis) {
+ PROC_STATE_CPU_TIMES_READ_DELAY_MS = newDelayMillis;
+ if (oldDelayMillis != newDelayMillis) {
+ mNumCpuTimeReads = 0;
+ mNumBatchedCpuTimeReads = 0;
+ mCpuTimeReadsTrackingStartTime = mClocks.uptimeMillis();
}
}
@@ -13202,6 +13270,8 @@ public class BatteryStatsImpl extends BatteryStats {
pw.println(TRACK_CPU_ACTIVE_CLUSTER_TIME);
pw.print(KEY_READ_BINARY_CPU_TIME); pw.print("=");
pw.println(READ_BINARY_CPU_TIME);
+ pw.print(KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS); pw.print("=");
+ pw.println(PROC_STATE_CPU_TIMES_READ_DELAY_MS);
}
}
@@ -14911,5 +14981,11 @@ public class BatteryStatsImpl extends BatteryStats {
mCameraOnTimer.logState(pr, " ");
}
super.dumpLocked(context, pw, flags, reqUid, histStart);
+ pw.print("Total cpu time reads: ");
+ pw.println(mNumCpuTimeReads);
+ pw.print("Batched cpu time reads: ");
+ pw.println(mNumBatchedCpuTimeReads);
+ pw.print("Batching Duration (min): ");
+ pw.println((mClocks.uptimeMillis() - mCpuTimeReadsTrackingStartTime) / (60 * 1000));
}
}
diff --git a/core/java/com/android/internal/os/KernelSingleUidTimeReader.java b/core/java/com/android/internal/os/KernelSingleUidTimeReader.java
index ebeb24c41479..42839171dc53 100644
--- a/core/java/com/android/internal/os/KernelSingleUidTimeReader.java
+++ b/core/java/com/android/internal/os/KernelSingleUidTimeReader.java
@@ -16,6 +16,7 @@
package com.android.internal.os;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+import static com.android.internal.os.KernelUidCpuFreqTimeReader.UID_TIMES_PROC_FILE;
import android.annotation.NonNull;
import android.util.Slog;
@@ -54,6 +55,12 @@ public class KernelSingleUidTimeReader {
private boolean mSingleUidCpuTimesAvailable = true;
@GuardedBy("this")
private boolean mHasStaleData;
+ // We use the freq count obtained from /proc/uid_time_in_state to decide how many longs
+ // to read from each /proc/uid/<uid>/time_in_state. On the first read, verify if this is
+ // correct and if not, set {@link #mSingleUidCpuTimesAvailable} to false. This flag will
+ // indicate whether we checked for validity or not.
+ @GuardedBy("this")
+ private boolean mCpuFreqsCountVerified;
private final Injector mInjector;
@@ -82,15 +89,15 @@ public class KernelSingleUidTimeReader {
final String procFile = new StringBuilder(PROC_FILE_DIR)
.append(uid)
.append(PROC_FILE_NAME).toString();
- final long[] cpuTimesMs = new long[mCpuFreqsCount];
+ final long[] cpuTimesMs;
try {
final byte[] data = mInjector.readData(procFile);
+ if (!mCpuFreqsCountVerified) {
+ verifyCpuFreqsCount(data.length, procFile);
+ }
final ByteBuffer buffer = ByteBuffer.wrap(data);
buffer.order(ByteOrder.nativeOrder());
- for (int i = 0; i < mCpuFreqsCount; ++i) {
- // Times read will be in units of 10ms
- cpuTimesMs[i] = buffer.getLong() * 10;
- }
+ cpuTimesMs = readCpuTimesFromByteBuffer(buffer);
} catch (Exception e) {
if (++mReadErrorCounter >= TOTAL_READ_ERROR_COUNT) {
mSingleUidCpuTimesAvailable = false;
@@ -103,6 +110,27 @@ public class KernelSingleUidTimeReader {
}
}
+ private void verifyCpuFreqsCount(int numBytes, String procFile) {
+ final int actualCount = (numBytes / Long.BYTES);
+ if (mCpuFreqsCount != actualCount) {
+ mSingleUidCpuTimesAvailable = false;
+ throw new IllegalStateException("Freq count didn't match,"
+ + "count from " + UID_TIMES_PROC_FILE + "=" + mCpuFreqsCount + ", but"
+ + "count from " + procFile + "=" + actualCount);
+ }
+ mCpuFreqsCountVerified = true;
+ }
+
+ private long[] readCpuTimesFromByteBuffer(ByteBuffer buffer) {
+ final long[] cpuTimesMs;
+ cpuTimesMs = new long[mCpuFreqsCount];
+ for (int i = 0; i < mCpuFreqsCount; ++i) {
+ // Times read will be in units of 10ms
+ cpuTimesMs[i] = buffer.getLong() * 10;
+ }
+ return cpuTimesMs;
+ }
+
/**
* Compute and return cpu times delta of an uid using previously read cpu times and
* {@param latestCpuTimesMs}.
diff --git a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
index b8982cce91b5..d97538c30498 100644
--- a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
@@ -49,7 +49,7 @@ import java.io.IOException;
public class KernelUidCpuFreqTimeReader {
private static final boolean DEBUG = false;
private static final String TAG = "KernelUidCpuFreqTimeReader";
- private static final String UID_TIMES_PROC_FILE = "/proc/uid_time_in_state";
+ static final String UID_TIMES_PROC_FILE = "/proc/uid_time_in_state";
public interface Callback {
void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs);
diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
index 65615c0ffb02..444049e7e415 100644
--- a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
@@ -78,10 +78,11 @@ public class KernelUidCpuTimeReader {
final long userTimeUs = Long.parseLong(splitter.next(), 10);
final long systemTimeUs = Long.parseLong(splitter.next(), 10);
+ boolean notifyCallback = false;
+ long userTimeDeltaUs = userTimeUs;
+ long systemTimeDeltaUs = systemTimeUs;
// Only report if there is a callback and if this is not the first read.
if (callback != null && mLastTimeReadUs != 0) {
- long userTimeDeltaUs = userTimeUs;
- long systemTimeDeltaUs = systemTimeUs;
int index = mLastUserTimeUs.indexOfKey(uid);
if (index >= 0) {
userTimeDeltaUs -= mLastUserTimeUs.valueAt(index);
@@ -114,12 +115,13 @@ public class KernelUidCpuTimeReader {
}
}
- if (userTimeDeltaUs != 0 || systemTimeDeltaUs != 0) {
- callback.onUidCpuTime(uid, userTimeDeltaUs, systemTimeDeltaUs);
- }
+ notifyCallback = (userTimeDeltaUs != 0 || systemTimeDeltaUs != 0);
}
mLastUserTimeUs.put(uid, userTimeUs);
mLastSystemTimeUs.put(uid, systemTimeUs);
+ if (notifyCallback) {
+ callback.onUidCpuTime(uid, userTimeDeltaUs, systemTimeDeltaUs);
+ }
}
} catch (IOException e) {
Slog.e(TAG, "Failed to read uid_cputime: " + e.getMessage());
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 895be082c679..bb5a0ad86dd4 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -230,7 +230,7 @@ public class RuntimeInit {
* @param argv Argument vector for main()
* @param classLoader the classLoader to load {@className} with
*/
- private static Runnable findStaticMain(String className, String[] argv,
+ protected static Runnable findStaticMain(String className, String[] argv,
ClassLoader classLoader) {
Class<?> cl;
diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java
index cadb66ae6e08..b38c851e5101 100644
--- a/core/java/com/android/internal/os/WebViewZygoteInit.java
+++ b/core/java/com/android/internal/os/WebViewZygoteInit.java
@@ -129,7 +129,7 @@ class WebViewZygoteInit {
final Runnable caller;
try {
- sServer.registerServerSocket("webview_zygote");
+ sServer.registerServerSocketFromEnv("webview_zygote");
// The select loop returns early in the child process after a fork and
// loops forever in the zygote.
caller = sServer.runSelectLoop(TextUtils.join(",", Build.SUPPORTED_ABIS));
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index e69a36064693..28a7c1204071 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -53,8 +53,8 @@ public final class Zygote {
public static final int DISABLE_VERIFIER = 1 << 9;
/** Only use oat files located in /system. Otherwise use dex/jar/apk . */
public static final int ONLY_USE_SYSTEM_OAT_FILES = 1 << 10;
- /** Do not enfore hidden API access restrictions. */
- public static final int DISABLE_HIDDEN_API_CHECKS = 1 << 11;
+ /** Do enfore hidden API access restrictions. */
+ public static final int ENABLE_HIDDEN_API_CHECKS = 1 << 11;
/** Force generation of native debugging information for backtraces. */
public static final int DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 12;
@@ -69,6 +69,13 @@ public final class Zygote {
private static final ZygoteHooks VM_HOOKS = new ZygoteHooks();
+ /**
+ * An extraArg passed when a zygote process is forking a child-zygote, specifying a name
+ * in the abstract socket namespace. This socket name is what the new child zygote
+ * should listen for connections on.
+ */
+ public static final String CHILD_ZYGOTE_SOCKET_NAME_ARG = "--zygote-socket=";
+
private Zygote() {}
/** Called for some security initialization before any fork. */
@@ -100,6 +107,8 @@ public final class Zygote {
* @param fdsToIgnore null-ok an array of ints, either null or holding
* one or more POSIX file descriptor numbers that are to be ignored
* in the file descriptor table check.
+ * @param startChildZygote if true, the new child process will itself be a
+ * new zygote process.
* @param instructionSet null-ok the instruction set to use.
* @param appDataDir null-ok the data directory of the app.
*
@@ -108,13 +117,13 @@ public final class Zygote {
*/
public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
- int[] fdsToIgnore, String instructionSet, String appDataDir) {
+ int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir) {
VM_HOOKS.preFork();
// Resets nice priority for zygote process.
resetNicePriority();
int pid = nativeForkAndSpecialize(
uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
- fdsToIgnore, instructionSet, appDataDir);
+ fdsToIgnore, startChildZygote, instructionSet, appDataDir);
// Enable tracing as soon as possible for the child process.
if (pid == 0) {
Trace.setTracingEnabled(true, runtimeFlags);
@@ -128,7 +137,7 @@ public final class Zygote {
native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int runtimeFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
- int[] fdsToIgnore, String instructionSet, String appDataDir);
+ int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir);
/**
* Called to do any initialization before starting an application.
@@ -160,9 +169,6 @@ public final class Zygote {
*/
public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
- // SystemServer is always allowed to use hidden APIs.
- runtimeFlags |= DISABLE_HIDDEN_API_CHECKS;
-
VM_HOOKS.preFork();
// Resets nice priority for zygote process.
resetNicePriority();
@@ -191,8 +197,8 @@ public final class Zygote {
native protected static void nativeUnmountStorageOnInit();
private static void callPostForkChildHooks(int runtimeFlags, boolean isSystemServer,
- String instructionSet) {
- VM_HOOKS.postForkChild(runtimeFlags, isSystemServer, instructionSet);
+ boolean isZygote, String instructionSet) {
+ VM_HOOKS.postForkChild(runtimeFlags, isSystemServer, isZygote, instructionSet);
}
/**
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 6a87b1f4d3fd..a32fb4316d12 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -221,8 +221,8 @@ class ZygoteConnection {
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
- parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
- parsedArgs.appDataDir);
+ parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
+ parsedArgs.instructionSet, parsedArgs.appDataDir);
try {
if (pid == 0) {
@@ -233,7 +233,8 @@ class ZygoteConnection {
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
- return handleChildProc(parsedArgs, descriptors, childPipeFd);
+ return handleChildProc(parsedArgs, descriptors, childPipeFd,
+ parsedArgs.startChildZygote);
} else {
// In the parent. A pid < 0 indicates a failure and will be handled in
// handleParentProc.
@@ -415,6 +416,14 @@ class ZygoteConnection {
boolean preloadDefault;
/**
+ * Whether this is a request to start a zygote process as a child of this zygote.
+ * Set with --start-child-zygote. The remaining arguments must include the
+ * CHILD_ZYGOTE_SOCKET_NAME_ARG flag to indicate the abstract socket name that
+ * should be used for communication.
+ */
+ boolean startChildZygote;
+
+ /**
* Constructs instance and parses args
* @param args zygote command-line args
* @throws IllegalArgumentException
@@ -565,6 +574,8 @@ class ZygoteConnection {
preloadPackageCacheKey = args[++curArg];
} else if (arg.equals("--preload-default")) {
preloadDefault = true;
+ } else if (arg.equals("--start-child-zygote")) {
+ startChildZygote = true;
} else {
break;
}
@@ -587,6 +598,20 @@ class ZygoteConnection {
remainingArgs = new String[args.length - curArg];
System.arraycopy(args, curArg, remainingArgs, 0, remainingArgs.length);
}
+
+ if (startChildZygote) {
+ boolean seenChildSocketArg = false;
+ for (String arg : remainingArgs) {
+ if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) {
+ seenChildSocketArg = true;
+ break;
+ }
+ }
+ if (!seenChildSocketArg) {
+ throw new IllegalArgumentException("--start-child-zygote specified " +
+ "without " + Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG);
+ }
+ }
}
}
@@ -739,9 +764,10 @@ class ZygoteConnection {
* @param parsedArgs non-null; zygote args
* @param descriptors null-ok; new file descriptors for stdio if available.
* @param pipeFd null-ok; pipe for communication back to Zygote.
+ * @param isZygote whether this new child process is itself a new Zygote.
*/
private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
- FileDescriptor pipeFd) {
+ FileDescriptor pipeFd, boolean isZygote) {
/**
* By the time we get here, the native code has closed the two actual Zygote
* socket connections, and substituted /dev/null in their place. The LocalSocket
@@ -778,8 +804,13 @@ class ZygoteConnection {
// Should not get here.
throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
} else {
- return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
- null /* classLoader */);
+ if (!isZygote) {
+ return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
+ null /* classLoader */);
+ } else {
+ return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
+ parsedArgs.remainingArgs, null /* classLoader */);
+ }
}
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 74802c8bdf79..c5d0a04b5deb 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -98,10 +98,6 @@ public class ZygoteInit {
private static final String SOCKET_NAME_ARG = "--socket-name=";
- /* Dexopt flag to disable hidden API access checks when dexopting SystemServer.
- * Must be kept in sync with com.android.server.pm.Installer. */
- private static final int DEXOPT_DISABLE_HIDDEN_API_CHECKS = 1 << 10;
-
/**
* Used to pre-load resources.
*/
@@ -569,10 +565,7 @@ public class ZygoteInit {
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
final String packageName = "*";
final String outputPath = null;
- // Dexopt with a flag which lifts restrictions on hidden API usage.
- // Offending methods would otherwise be re-verified at runtime and
- // we want to avoid the performance overhead of that.
- final int dexFlags = DEXOPT_DISABLE_HIDDEN_API_CHECKS;
+ final int dexFlags = 0;
final String compilerFilter = systemServerFilter;
final String uuid = StorageManager.UUID_PRIVATE_INTERNAL;
final String seInfo = null;
@@ -583,7 +576,8 @@ public class ZygoteInit {
installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
uuid, classLoaderContext, seInfo, false /* downgrade */,
- targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null);
+ targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null,
+ "server-dexopt");
} catch (RemoteException | ServiceSpecificException e) {
// Ignore (but log), we need this on the classpath for fallback mode.
Log.w(TAG, "Failed compiling classpath element for system server: "
@@ -762,7 +756,7 @@ public class ZygoteInit {
throw new RuntimeException("No ABI list supplied.");
}
- zygoteServer.registerServerSocket(socketName);
+ zygoteServer.registerServerSocketFromEnv(socketName);
// In some configurations, we avoid preloading resources and classes eagerly.
// In such cases, we will preload things prior to our first fork.
if (!enableLazyPreload) {
@@ -877,5 +871,16 @@ public class ZygoteInit {
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
+ /**
+ * The main function called when starting a child zygote process. This is used as an
+ * alternative to zygoteInit(), which skips calling into initialization routines that
+ * start the Binder threadpool.
+ */
+ static final Runnable childZygoteInit(
+ int targetSdkVersion, String[] argv, ClassLoader classLoader) {
+ RuntimeInit.Arguments args = new RuntimeInit.Arguments(argv);
+ return RuntimeInit.findStaticMain(args.startClass, args.startArgs, classLoader);
+ }
+
private static final native void nativeZygoteInit();
}
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
index 8baa15a058de..fecf9b9da5dd 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -44,9 +44,21 @@ class ZygoteServer {
private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
+ /**
+ * Listening socket that accepts new server connections.
+ */
private LocalServerSocket mServerSocket;
/**
+ * Whether or not mServerSocket's underlying FD should be closed directly.
+ * If mServerSocket is created with an existing FD, closing the socket does
+ * not close the FD and it must be closed explicitly. If the socket is created
+ * with a name instead, then closing the socket will close the underlying FD
+ * and it should not be double-closed.
+ */
+ private boolean mCloseSocketFd;
+
+ /**
* Set by the child process, immediately after a call to {@code Zygote.forkAndSpecialize}.
*/
private boolean mIsForkChild;
@@ -59,11 +71,12 @@ class ZygoteServer {
}
/**
- * Registers a server socket for zygote command connections
+ * Registers a server socket for zygote command connections. This locates the server socket
+ * file descriptor through an ANDROID_SOCKET_ environment variable.
*
* @throws RuntimeException when open fails
*/
- void registerServerSocket(String socketName) {
+ void registerServerSocketFromEnv(String socketName) {
if (mServerSocket == null) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
@@ -78,6 +91,7 @@ class ZygoteServer {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
mServerSocket = new LocalServerSocket(fd);
+ mCloseSocketFd = true;
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
@@ -86,6 +100,22 @@ class ZygoteServer {
}
/**
+ * Registers a server socket for zygote command connections. This opens the server socket
+ * at the specified name in the abstract socket namespace.
+ */
+ void registerServerSocketAtAbstractName(String socketName) {
+ if (mServerSocket == null) {
+ try {
+ mServerSocket = new LocalServerSocket(socketName);
+ mCloseSocketFd = false;
+ } catch (IOException ex) {
+ throw new RuntimeException(
+ "Error binding to abstract socket '" + socketName + "'", ex);
+ }
+ }
+ }
+
+ /**
* Waits for and accepts a single command connection. Throws
* RuntimeException on failure.
*/
@@ -112,7 +142,7 @@ class ZygoteServer {
if (mServerSocket != null) {
FileDescriptor fd = mServerSocket.getFileDescriptor();
mServerSocket.close();
- if (fd != null) {
+ if (fd != null && mCloseSocketFd) {
Os.close(fd);
}
}
@@ -219,6 +249,11 @@ class ZygoteServer {
Log.e(TAG, "Caught post-fork exception in child process.", e);
throw e;
}
+ } finally {
+ // Reset the child flag, in the event that the child process is a child-
+ // zygote. The flag will not be consulted this loop pass after the Runnable
+ // is returned.
+ mIsForkChild = false;
}
}
}
diff --git a/core/java/com/android/internal/print/DumpUtils.java b/core/java/com/android/internal/print/DumpUtils.java
index 1916c11e9c9d..f44a1d122f39 100644
--- a/core/java/com/android/internal/print/DumpUtils.java
+++ b/core/java/com/android/internal/print/DumpUtils.java
@@ -213,10 +213,9 @@ public class DumpUtils {
PrintAttributes.MediaSize mediaSize = attributes.getMediaSize();
if (mediaSize != null) {
writeMediaSize(context, proto, "media_size", PrintAttributesProto.MEDIA_SIZE, mediaSize);
+ proto.write("is_portrait", PrintAttributesProto.IS_PORTRAIT, attributes.isPortrait());
}
- proto.write("is_portrait", PrintAttributesProto.IS_PORTRAIT, attributes.isPortrait());
-
PrintAttributes.Resolution res = attributes.getResolution();
if (res != null) {
writeResolution(proto, "resolution", PrintAttributesProto.RESOLUTION, res);
diff --git a/core/java/com/android/internal/util/OWNERS b/core/java/com/android/internal/util/OWNERS
new file mode 100644
index 000000000000..21d750c59a4e
--- /dev/null
+++ b/core/java/com/android/internal/util/OWNERS
@@ -0,0 +1,24 @@
+per-file AsyncChannel*=lorenzo@google.com
+per-file AsyncChannel*=satk@google.com
+per-file AsyncChannel*=silberst@google.com
+per-file BitUtils*=ek@google.com
+per-file BitUtils*=lorenzo@google.com
+per-file BitUtils*=satk@google.com
+per-file MessageUtils*=ek@google.com
+per-file MessageUtils*=lorenzo@google.com
+per-file MessageUtils*=satk@google.com
+per-file Protocol*=ek@google.com
+per-file Protocol*=lorenzo@google.com
+per-file Protocol*=quiche@google.com
+per-file Protocol*=satk@google.com
+per-file Protocol*=silberst@google.com
+per-file RingBuffer*=ek@google.com
+per-file RingBuffer*=lorenzo@google.com
+per-file RingBuffer*=satk@google.com
+per-file State*=ek@google.com
+per-file State*=lorenzo@google.com
+per-file State*=quiche@google.com
+per-file State*=silberst@google.com
+per-file TokenBucket*=ek@google.com
+per-file TokenBucket*=lorenzo@google.com
+per-file TokenBucket*=satk@google.com
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
new file mode 100644
index 000000000000..ce79049a195d
--- /dev/null
+++ b/core/jni/OWNERS
@@ -0,0 +1,12 @@
+# Camera
+per-file *Camera*,*camera* = cychen@google.com
+per-file *Camera*,*camera* = epeev@google.com
+per-file *Camera*,*camera* = etalvala@google.com
+per-file *Camera*,*camera* = shuzhenwang@google.com
+per-file *Camera*,*camera* = yinchiayeh@google.com
+per-file *Camera*,*camera* = zhijunhe@google.com
+
+# Connectivity
+per-file android_net_*=ek@google.com
+per-file android_net_*=lorenzo@google.com
+per-file android_net_*=satk@google.com
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index d6f8dc45560c..61d5031e16ed 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -604,6 +604,7 @@ static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
CameraInfo cameraInfo;
status_t rc = Camera::getCameraInfo(cameraId, &cameraInfo);
if (rc != NO_ERROR) {
+ ALOGE("%s: getCameraInfo error: %d", __FUNCTION__, rc);
return rc;
}
int defaultOrientation = 0;
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 5b788a644852..d17993a72aaf 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -663,7 +663,8 @@ jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get());
if (env->ExceptionCheck()) {
- gNativeDataCache = nativeData;
+ // In the exception case, getInstance still took ownership of nativeData.
+ gNativeDataCache = nullptr;
return NULL;
}
BinderProxyNativeData* actualNativeData = getBPNativeData(env, object);
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 32945bfbceb1..d6fe5687edb9 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -516,7 +516,7 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
jint mount_external,
jstring java_se_info, jstring java_se_name,
bool is_system_server, jintArray fdsToClose,
- jintArray fdsToIgnore,
+ jintArray fdsToIgnore, bool is_child_zygote,
jstring instructionSet, jstring dataDir) {
SetSignalHandlers();
@@ -699,7 +699,7 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
UnsetChldSignalHandler();
env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
- is_system_server, instructionSet);
+ is_system_server, is_child_zygote, instructionSet);
if (env->ExceptionCheck()) {
RuntimeAbort(env, __LINE__, "Error calling post fork hooks.");
}
@@ -748,8 +748,7 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
jint runtime_flags, jobjectArray rlimits,
jint mount_external, jstring se_info, jstring se_name,
- jintArray fdsToClose,
- jintArray fdsToIgnore,
+ jintArray fdsToClose, jintArray fdsToIgnore, jboolean is_child_zygote,
jstring instructionSet, jstring appDataDir) {
jlong capabilities = 0;
@@ -786,13 +785,22 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
capabilities |= (1LL << CAP_BLOCK_SUSPEND);
}
+ // If forking a child zygote process, that zygote will need to be able to change
+ // the UID and GID of processes it forks, as well as drop those capabilities.
+ if (is_child_zygote) {
+ capabilities |= (1LL << CAP_SETUID);
+ capabilities |= (1LL << CAP_SETGID);
+ capabilities |= (1LL << CAP_SETPCAP);
+ }
+
// Containers run without some capabilities, so drop any caps that are not
// available.
capabilities &= GetEffectiveCapabilityMask(env);
return ForkAndSpecializeCommon(env, uid, gid, gids, runtime_flags,
rlimits, capabilities, capabilities, mount_external, se_info,
- se_name, false, fdsToClose, fdsToIgnore, instructionSet, appDataDir);
+ se_name, false, fdsToClose, fdsToIgnore, is_child_zygote == JNI_TRUE,
+ instructionSet, appDataDir);
}
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
@@ -803,7 +811,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer(
runtime_flags, rlimits,
permittedCapabilities, effectiveCapabilities,
MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
- NULL, NULL, NULL);
+ NULL, false, NULL, NULL);
if (pid > 0) {
// The zygote process checks whether the child process has died or not.
ALOGI("System server process %d has been created", pid);
@@ -880,7 +888,7 @@ static const JNINativeMethod gMethods[] = {
{ "nativeSecurityInit", "()V",
(void *) com_android_internal_os_Zygote_nativeSecurityInit },
{ "nativeForkAndSpecialize",
- "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[ILjava/lang/String;Ljava/lang/String;)I",
+ "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I",
(void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
{ "nativeForkSystemServer", "(II[II[[IJJ)I",
(void *) com_android_internal_os_Zygote_nativeForkSystemServer },
@@ -895,7 +903,7 @@ static const JNINativeMethod gMethods[] = {
int register_com_android_internal_os_Zygote(JNIEnv* env) {
gZygoteClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, kZygoteClassName));
gCallPostForkChildHooks = GetStaticMethodIDOrDie(env, gZygoteClass, "callPostForkChildHooks",
- "(IZLjava/lang/String;)V");
+ "(IZZLjava/lang/String;)V");
return RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods));
}
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 3b7b14c58d0a..2e6058268115 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -317,10 +317,12 @@ bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) {
return false;
}
- // This is a local socket with an abstract address, we do not accept it.
+ // This is a local socket with an abstract address. Remove the leading NUL byte and
+ // add a human-readable "ABSTRACT/" prefix.
if (unix_addr->sun_path[0] == '\0') {
- LOG(ERROR) << "Unsupported AF_UNIX socket (fd=" << fd << ") with abstract address.";
- return false;
+ *result = "ABSTRACT/";
+ result->append(&unix_addr->sun_path[1], path_len - 1);
+ return true;
}
// If we're here, sun_path must refer to a null terminated filesystem
diff --git a/core/proto/android/net/OWNERS b/core/proto/android/net/OWNERS
new file mode 100644
index 000000000000..a845dcbec661
--- /dev/null
+++ b/core/proto/android/net/OWNERS
@@ -0,0 +1,5 @@
+set noparent
+
+ek@google.com
+lorenzo@google.com
+satk@google.com
diff --git a/core/proto/android/os/cpufreq.proto b/core/proto/android/os/cpufreq.proto
index 8481ffc112d4..46f4901d8a29 100644
--- a/core/proto/android/os/cpufreq.proto
+++ b/core/proto/android/os/cpufreq.proto
@@ -16,32 +16,30 @@
syntax = "proto2";
option java_multiple_files = true;
-option java_outer_classname = "CpuFreqProto";
import "frameworks/base/libs/incident/proto/android/privacy.proto";
package android.os;
// cpu frequency time from /sys/devices/system/cpu/cpufreq/all_time_in_state
-message CpuFreq {
+message CpuFreqProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
optional int32 jiffy_hz = 1; // obtain by system config.
- repeated CpuFreqStats cpu_freqs = 2;
-}
-
-// frequency time pre cpu, unit in jiffy, TODO: obtain jiffies.
-message CpuFreqStats {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ // frequency time pre cpu, unit in jiffy.
+ message Stats {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
- optional string cpu_name = 1;
+ optional string cpu_name = 1;
- message TimeInState {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ message TimeInState {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
- optional int32 state_khz = 1; // cpu frequency
- optional int64 time_jiffy = 2; // number of jiffies
+ optional int32 state_khz = 1; // cpu frequency
+ optional int64 time_jiffy = 2; // number of jiffies
+ }
+ repeated TimeInState times = 2;
}
- repeated TimeInState times = 2;
+ repeated Stats cpu_freqs = 2;
}
diff --git a/core/proto/android/os/cpuinfo.proto b/core/proto/android/os/cpuinfo.proto
index ca4360238c6b..ce69fc9d4037 100644
--- a/core/proto/android/os/cpuinfo.proto
+++ b/core/proto/android/os/cpuinfo.proto
@@ -16,7 +16,6 @@
syntax = "proto2";
option java_multiple_files = true;
-option java_outer_classname = "CpuInfoProto";
import "frameworks/base/libs/incident/proto/android/privacy.proto";
@@ -28,7 +27,7 @@ package android.os;
*
* Next Tag: 6
*/
-message CpuInfo {
+message CpuInfoProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
message TaskStats {
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 698f394385ab..9a53b89ffe30 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -46,18 +46,12 @@ import "frameworks/base/core/proto/android/service/usb.proto";
import "frameworks/base/core/proto/android/util/event_log_tags.proto";
import "frameworks/base/core/proto/android/util/log.proto";
import "frameworks/base/libs/incident/proto/android/os/header.proto";
+import "frameworks/base/libs/incident/proto/android/os/metadata.proto";
import "frameworks/base/libs/incident/proto/android/privacy.proto";
import "frameworks/base/libs/incident/proto/android/section.proto";
package android.os;
-// This field contains internal metadata associated with an incident report,
-// such as the section ids and privacy policy specs from caller as well as how long
-// and how many bytes a section takes, etc.
-message IncidentMetadata {
-
-}
-
// privacy field options must not be set at this level because all
// the sections are able to be controlled and configured by section ids.
// Instead privacy field options need to be configured in each section proto message.
@@ -122,32 +116,32 @@ message IncidentProto {
];
// Linux services
- optional Procrank procrank = 2000 [
+ optional ProcrankProto procrank = 2000 [
(section).type = SECTION_NONE, // disable procrank until figure out permission
(section).args = "/system/xbin/procrank"
];
- optional PageTypeInfo page_type_info = 2001 [
+ optional PageTypeInfoProto page_type_info = 2001 [
(section).type = SECTION_FILE,
(section).args = "/proc/pagetypeinfo"
];
- optional KernelWakeSources kernel_wake_sources = 2002 [
+ optional KernelWakeSourcesProto kernel_wake_sources = 2002 [
(section).type = SECTION_FILE,
(section).args = "/d/wakeup_sources"
];
- optional CpuInfo cpu_info = 2003 [
+ optional CpuInfoProto cpu_info = 2003 [
(section).type = SECTION_COMMAND,
(section).args = "top -b -n 1 -H -s 6 -o pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"
];
- optional CpuFreq cpu_freq = 2004 [
+ optional CpuFreqProto cpu_freq = 2004 [
(section).type = SECTION_FILE,
(section).args = "/sys/devices/system/cpu/cpufreq/all_time_in_state"
];
- optional PsDumpProto processes_and_threads = 2005 [
+ optional PsProto processes_and_threads = 2005 [
(section).type = SECTION_COMMAND,
(section).args = "ps -A -T -Z -O pri,nice,rtprio,sched,pcy,time"
];
diff --git a/core/proto/android/os/kernelwake.proto b/core/proto/android/os/kernelwake.proto
index c296dab5a1ef..5021a06b1769 100644
--- a/core/proto/android/os/kernelwake.proto
+++ b/core/proto/android/os/kernelwake.proto
@@ -16,41 +16,40 @@
syntax = "proto2";
option java_multiple_files = true;
-option java_outer_classname = "WakeupSourcesProto";
import "frameworks/base/libs/incident/proto/android/privacy.proto";
package android.os;
-message KernelWakeSources {
+message KernelWakeSourcesProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
// Kernel records of what caused the application processor to wake up
- repeated WakeupSourceProto wakeup_sources = 1;
-}
+ message WakeupSource {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
-// Next Tag: 11
-message WakeupSourceProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ // Name of the event which triggers application processor
+ optional string name = 1;
- // Name of the event which triggers application processor
- optional string name = 1;
+ optional int32 active_count = 2;
- optional int32 active_count = 2;
+ optional int32 event_count = 3;
- optional int32 event_count = 3;
+ optional int32 wakeup_count = 4;
- optional int32 wakeup_count = 4;
+ optional int32 expire_count = 5;
- optional int32 expire_count = 5;
+ optional int64 active_since = 6;
- optional int64 active_since = 6;
+ optional int64 total_time = 7;
- optional int64 total_time = 7;
+ optional int64 max_time = 8;
- optional int64 max_time = 8;
+ optional int64 last_change = 9;
- optional int64 last_change = 9;
+ optional int64 prevent_suspend_time = 10;
- optional int64 prevent_suspend_time = 10;
+ // Next Tag: 11
+ }
+ repeated WakeupSource wakeup_sources = 1;
}
diff --git a/core/proto/android/os/pagetypeinfo.proto b/core/proto/android/os/pagetypeinfo.proto
index b8f618b5d4c2..f5d77d637733 100644
--- a/core/proto/android/os/pagetypeinfo.proto
+++ b/core/proto/android/os/pagetypeinfo.proto
@@ -16,7 +16,6 @@
syntax = "proto2";
option java_multiple_files = true;
-option java_outer_classname = "PageTypeInfoProto";
import "frameworks/base/libs/incident/proto/android/privacy.proto";
@@ -37,49 +36,47 @@ package android.os;
*
* Next tag: 5
*/
-message PageTypeInfo {
+message PageTypeInfoProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
optional int32 page_block_order = 1;
optional int32 pages_per_block = 2;
- repeated MigrateTypeProto migrate_types = 3;
+ // Next tag: 5
+ message MigrateType {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
- repeated BlockProto blocks = 4;
-}
-
-// Next tag: 5
-message MigrateTypeProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ optional int32 node = 1;
- optional int32 node = 1;
+ optional string zone = 2;
- optional string zone = 2;
+ optional string type = 3;
- optional string type = 3;
+ // order level starts from 0 for 4KB to page_block_order defined above, e.g. 10 for 4096KB
+ repeated int32 free_pages_count = 4;
+ }
+ repeated MigrateType migrate_types = 3;
- // order level starts from 0 for 4KB to page_block_order defined above, e.g. 10 for 4096KB
- repeated int32 free_pages_count = 4;
-}
-
-// Next tag: 9
-message BlockProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ // Next tag: 9
+ message Block {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
- optional int32 node = 1;
+ optional int32 node = 1;
- optional string zone = 2;
+ optional string zone = 2;
- optional int32 unmovable = 3;
+ optional int32 unmovable = 3;
- optional int32 reclaimable = 4;
+ optional int32 reclaimable = 4;
- optional int32 movable = 5;
+ optional int32 movable = 5;
- optional int32 cma = 6;
+ optional int32 cma = 6;
- optional int32 reserve = 7;
+ optional int32 reserve = 7;
- optional int32 isolate = 8;
+ optional int32 isolate = 8;
+ }
+ repeated Block blocks = 4;
}
diff --git a/core/proto/android/os/procrank.proto b/core/proto/android/os/procrank.proto
index 204a5af70947..ff7515e61471 100644
--- a/core/proto/android/os/procrank.proto
+++ b/core/proto/android/os/procrank.proto
@@ -16,78 +16,73 @@
syntax = "proto2";
option java_multiple_files = true;
-option java_outer_classname = "ProcrankProto";
import "frameworks/base/libs/incident/proto/android/privacy.proto";
package android.os;
//Memory usage of running processes
-message Procrank {
+message ProcrankProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
// Currently running process
- repeated ProcessProto processes = 1;
+ // Next Tag: 11
+ message Process {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
- // Summary
- optional SummaryProto summary = 2;
-}
-
-// Next Tag: 11
-message ProcessProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
- // ID of the process
- optional int32 pid = 1;
-
- // virtual set size, unit KB
- optional int64 vss = 2;
-
- // resident set size, unit KB
- optional int64 rss = 3;
+ // ID of the process
+ optional int32 pid = 1;
- // proportional set size, unit KB
- optional int64 pss = 4;
+ // virtual set size, unit KB
+ optional int64 vss = 2;
- // unique set size, unit KB
- optional int64 uss = 5;
+ // resident set size, unit KB
+ optional int64 rss = 3;
- // swap size, unit KB
- optional int64 swap = 6;
+ // proportional set size, unit KB
+ optional int64 pss = 4;
- // proportional swap size, unit KB
- optional int64 pswap = 7;
+ // unique set size, unit KB
+ optional int64 uss = 5;
- // unique swap size, unit KB
- optional int64 uswap = 8;
+ // swap size, unit KB
+ optional int64 swap = 6;
- // zswap size, unit KB
- optional int64 zswap = 9;
+ // proportional swap size, unit KB
+ optional int64 pswap = 7;
- // process command
- optional string cmdline = 10;
-}
+ // unique swap size, unit KB
+ optional int64 uswap = 8;
-// Next Tag: 3
-message SummaryProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ // zswap size, unit KB
+ optional int64 zswap = 9;
- optional ProcessProto total = 1;
+ // process command
+ optional string cmdline = 10;
+ }
+ repeated Process processes = 1;
- optional ZramProto zram = 2;
+ // Summary
+ // Next Tag: 3
+ message Summary {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
- optional RamProto ram = 3;
-}
+ optional Process total = 1;
-// TODO: sync on how to use these values
-message ZramProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ // TODO: sync on how to use these values
+ message Zram {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
- optional string raw_text = 1;
-}
+ optional string raw_text = 1;
+ }
+ optional Zram zram = 2;
-message RamProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ message Ram {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
- optional string raw_text = 1;
+ optional string raw_text = 1;
+ }
+ optional Ram ram = 3;
+ }
+ optional Summary summary = 2;
}
diff --git a/core/proto/android/os/ps.proto b/core/proto/android/os/ps.proto
index 9cce7274d000..0ab92d7686c7 100644
--- a/core/proto/android/os/ps.proto
+++ b/core/proto/android/os/ps.proto
@@ -22,7 +22,7 @@ option java_multiple_files = true;
import "frameworks/base/libs/incident/proto/android/privacy.proto";
-message PsDumpProto {
+message PsProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
message Process {
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index f2b7ab297e20..6b92aa8e8ffa 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -399,6 +399,7 @@ message GlobalSettingsProto {
optional SettingProto euicc_factory_reset_timeout_millis = 333 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto storage_settings_clobber_threshold = 334 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto chained_battery_attribution_enabled = 353 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto hidden_api_blacklist_exemptions = 355 [ (android.privacy).dest = DEST_AUTOMATIC ];
// Subscription to be used for voice call on a multi sim device. The
// supported values are 0 = SUB1, 1 = SUB2 and etc.
optional SettingProto multi_sim_voice_call_subscription = 276 [ (android.privacy).dest = DEST_AUTOMATIC ];
@@ -421,15 +422,18 @@ message GlobalSettingsProto {
optional SettingProto enable_deletion_helper_no_threshold_toggle = 340 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto notification_snooze_options = 341 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto enable_gnss_raw_meas_full_tracking = 346 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto install_carrier_app_notification_persistent = 356 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto install_carrier_app_notification_sleep_millis = 357 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto zram_enabled = 347 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto smart_replies_in_notifications_flags = 348 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto show_first_crash_dialog = 349 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto show_restart_in_crash_dialog = 351 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto show_mute_in_crash_dialog = 352 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingsProto show_zen_upgrade_notification = 354 [ (android.privacy).dest = DEST_AUTOMATIC ];
// Please insert fields in the same order as in
// frameworks/base/core/java/android/provider/Settings.java.
- // Next tag = 354;
+ // Next tag = 356;
}
message SecureSettingsProto {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6f3c25fa8194..3a527b59d074 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -174,6 +174,10 @@
<protected-broadcast
android:name="android.bluetooth.headsetclient.profile.action.LAST_VTAG" />
<protected-broadcast
+ android:name="android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED" />
+ <protected-broadcast
android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.a2dp.profile.action.ACTIVE_DEVICE_CHANGED" />
diff --git a/core/res/res/values-watch/colors_material.xml b/core/res/res/color-watch/btn_watch_default_dark.xml
index b19820c4bbbe..68b0eb60b786 100644
--- a/core/res/res/values-watch/colors_material.xml
+++ b/core/res/res/color-watch/btn_watch_default_dark.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,9 +13,10 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
- <!-- referenced in colors/watch_btn_default.xml selector -->
- <color name="button_material_dark">#ff919699</color>
-
-</resources>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false"
+ android:alpha="?attr/disabledAlpha"
+ android:color="?attr/colorPrimaryDark"/>
+ <item android:color="?attr/colorPrimaryDark"/>
+</selector>
diff --git a/core/res/res/color/watch_switch_thumb_color_material.xml b/core/res/res/color-watch/switch_thumb_watch_default_dark.xml
index f78d9b62a509..a553fa942681 100644
--- a/core/res/res/color/watch_switch_thumb_color_material.xml
+++ b/core/res/res/color-watch/switch_thumb_watch_default_dark.xml
@@ -11,8 +11,8 @@
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="?attr/colorButtonNormal" android:alpha="?attr/disabledAlpha"
+ <item android:color="?attr/colorPrimary" android:alpha="?attr/disabledAlpha"
android:state_enabled="false" />
<item android:color="?attr/colorControlActivated" android:state_checked="true" />
- <item android:color="?attr/colorButtonNormal" />
+ <item android:color="?attr/colorPrimary" />
</selector>
diff --git a/core/res/res/color/watch_switch_track_color_material.xml b/core/res/res/color-watch/switch_track_watch_default_dark.xml
index c7dc5d34204a..15bbedab6b6c 100644
--- a/core/res/res/color/watch_switch_track_color_material.xml
+++ b/core/res/res/color-watch/switch_track_watch_default_dark.xml
@@ -17,6 +17,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false"
android:alpha="?attr/disabledAlpha"
- android:color="?android:colorPrimary" />
- <item android:color="?android:colorPrimary" />
-</selector> \ No newline at end of file
+ android:color="?android:colorPrimaryDark" />
+ <item android:color="?android:colorPrimaryDark" />
+</selector>
diff --git a/core/res/res/drawable/watch_switch_thumb_material_anim.xml b/core/res/res/drawable-watch/switch_thumb_watch_default_dark_anim.xml
index 9e3e89338dab..9e3e89338dab 100644
--- a/core/res/res/drawable/watch_switch_thumb_material_anim.xml
+++ b/core/res/res/drawable-watch/switch_thumb_watch_default_dark_anim.xml
diff --git a/core/res/res/drawable/ic_settings_24dp.xml b/core/res/res/drawable/ic_settings_24dp.xml
index fc75f04ff46b..c70b122358b8 100644
--- a/core/res/res/drawable/ic_settings_24dp.xml
+++ b/core/res/res/drawable/ic_settings_24dp.xml
@@ -16,9 +16,9 @@ Copyright (C) 2015 The Android Open Source Project
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
<path
- android:fillColor="#FF000000"
- android:pathData="M38.86 25.95c.08,-.64.14,-1.29.14,-1.95s-.06,-1.31,-.14,-1.95l4.23,-3.31c.38,-.3.49,-.84.24,-1.28l-4,-6.93c-.25,-.43,-.77,-.61,-1.22,-.43l-4.98 2.01c-1.03,-.79,-2.16,-1.46,-3.38,-1.97L29 4.84c-.09,-.47,-.5,-.84,-1,-.84h-8c-.5 0,-.91.37,-.99.84l-.75 5.3c-1.22.51,-2.35 1.17,-3.38 1.97L9.9 10.1c-.45,-.17,-.97 0,-1.22.43l-4 6.93c-.25.43,-.14.97.24 1.28l4.22 3.31C9.06 22.69 9 23.34 9 24s.06 1.31.14 1.95l-4.22 3.31c-.38.3,-.49.84,-.24 1.28l4 6.93c.25.43.77.61 1.22.43l4.98,-2.01c1.03.79 2.16 1.46 3.38 1.97l.75 5.3c.08.47.49.84.99.84h8c.5 0 .91,-.37.99,-.84l.75,-5.3c1.22,-.51 2.35,-1.17 3.38,-1.97l4.98 2.01c.45.17.97 0 1.22,-.43l4,-6.93c.25,-.43.14,-.97,-.24,-1.28l-4.22,-3.31zM24 31c-3.87 0,-7,-3.13,-7,-7s3.13,-7 7,-7 7 3.13 7 7,-3.13 7,-7 7z"/>
+ android:pathData="M19.4,13.0c0.0,-0.3 0.1,-0.6 0.1,-1.0s0.0,-0.7 -0.1,-1.0l2.1,-1.7c0.2,-0.2 0.2,-0.4 0.1,-0.6l-2.0,-3.5C19.5,5.1 19.3,5.0 19.0,5.1l-2.5,1.0c-0.5,-0.4 -1.1,-0.7 -1.7,-1.0l-0.4,-2.6C14.5,2.2 14.2,2.0 14.0,2.0l-4.0,0.0C9.8,2.0 9.5,2.2 9.5,2.4L9.1,5.1C8.5,5.3 8.0,5.7 7.4,6.1L5.0,5.1C4.7,5.0 4.5,5.1 4.3,5.3l-2.0,3.5C2.2,8.9 2.3,9.2 2.5,9.4L4.6,11.0c0.0,0.3 -0.1,0.6 -0.1,1.0s0.0,0.7 0.1,1.0l-2.1,1.7c-0.2,0.2 -0.2,0.4 -0.1,0.6l2.0,3.5C4.5,18.9 4.7,19.0 5.0,18.9l2.5,-1.0c0.5,0.4 1.1,0.7 1.7,1.0l0.4,2.6c0.0,0.2 0.2,0.4 0.5,0.4l4.0,0.0c0.2,0.0 0.5,-0.2 0.5,-0.4l0.4,-2.6c0.6,-0.3 1.2,-0.6 1.7,-1.0l2.5,1.0c0.2,0.1 0.5,0.0 0.6,-0.2l2.0,-3.5c0.1,-0.2 0.1,-0.5 -0.1,-0.6L19.4,13.0zM12.0,15.5c-1.9,0.0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5s3.5,1.6 3.5,3.5S13.9,15.5 12.0,15.5z"
+ android:fillColor="#FF000000" />
</vector>
diff --git a/core/res/res/drawable/ic_signal_cellular_alt_24px.xml b/core/res/res/drawable/ic_signal_cellular_alt_24px.xml
new file mode 100644
index 000000000000..29f1f431c199
--- /dev/null
+++ b/core/res/res/drawable/ic_signal_cellular_alt_24px.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="21dp"
+ android:viewportWidth="20"
+ android:viewportHeight="21">
+
+ <group
+ android:translateX="-31.000000"
+ android:translateY="-77.000000">
+ <group
+ android:translateX="24.000000"
+ android:translateY="72.000000">
+ <path
+ android:fillType="evenOdd"
+ android:strokeWidth="1"
+ android:pathData="M 0 0 H 32 V 32 H 0 V 0 Z" />
+ <path
+ android:fillColor="#4285F4"
+ android:strokeWidth="1"
+ android:pathData="M23,5 L27,5 L27,26 L23,26 L23,5 Z M7,18.125 L11,18.125 L11,26 L7,26 L7,18.125 Z
+M15,11.5625 L19,11.5625 L19,26 L15,26 L15,11.5625 Z" />
+ </group>
+ </group>
+</vector> \ No newline at end of file
diff --git a/core/res/res/layout-watch/preference_widget_switch.xml b/core/res/res/layout-watch/preference_widget_switch.xml
index a1a845abfe3a..1f9d67858e56 100644
--- a/core/res/res/layout-watch/preference_widget_switch.xml
+++ b/core/res/res/layout-watch/preference_widget_switch.xml
@@ -21,11 +21,11 @@
android:layout_height="40dp"
android:switchMinWidth="40dp"
android:layout_gravity="center"
- android:thumb="@drawable/watch_switch_thumb_material_anim"
- android:thumbTint="@color/watch_switch_thumb_color_material"
+ android:thumb="@drawable/switch_thumb_watch_default_dark_anim"
+ android:thumbTint="@color/switch_thumb_watch_default_dark"
android:thumbTintMode="multiply"
android:track="@drawable/watch_switch_track_mtrl"
- android:trackTint="@color/watch_switch_track_color_material"
+ android:trackTint="@color/switch_track_watch_default_dark"
android:focusable="false"
android:clickable="false"
android:background="@null" />
diff --git a/core/res/res/layout/autofill_dataset_picker_fullscreen.xml b/core/res/res/layout/autofill_dataset_picker_fullscreen.xml
new file mode 100644
index 000000000000..07298c182269
--- /dev/null
+++ b/core/res/res/layout/autofill_dataset_picker_fullscreen.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/autofill_dataset_picker"
+ style="@style/AutofillDatasetPicker"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/autofill_window_title"
+ android:layout_above="@+id/autofill_dataset_container"
+ android:layout_alignStart="@+id/autofill_dataset_container"
+ android:textSize="16sp"/>
+
+ <!-- autofill_container is the common parent for inserting authentication item or
+ autofill_dataset_list-->
+ <FrameLayout
+ android:id="@+id/autofill_dataset_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true">
+ <ListView
+ android:id="@+id/autofill_dataset_list"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clickable="true"
+ android:divider="@null"
+ android:drawSelectorOnTop="true"
+ android:visibility="gone"/>
+ </FrameLayout>
+
+</RelativeLayout>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index df0f578ee0ea..ba64d0f7112f 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -264,10 +264,8 @@
<string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
<string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
- <!-- no translation found for user_owner_label (8836124313744349203) -->
- <skip />
- <!-- no translation found for managed_profile_label (8947929265267690522) -->
- <skip />
+ <string name="user_owner_label" msgid="8836124313744349203">"Skift til personlig profil"</string>
+ <string name="managed_profile_label" msgid="8947929265267690522">"Skift til arbejdsprofil"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktpersoner"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"have adgang til dine kontaktpersoner"</string>
<string name="permgrouprequest_contacts" msgid="1601591667800538208">"Giv &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til dine kontaktpersoner"</string>
@@ -357,6 +355,8 @@
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Tillader, at appen gør dele af sig selv vedholdende i hukommelsen. Dette kan begrænse den tilgængelige hukommelse for andre apps, hvilket gør tabletten langsommere."</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Giver appen lov til at gøre dele af sig selv vedholdende i hukommelsen. Dette kan begrænse den tilgængelige hukommelse for andre apps og derved gøre fjernsynet langsommere."</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Tillader, at appen gør dele af sig selv vedholdende i hukommelsen. Dette kan begrænse den tilgængelige hukommelse for andre apps, hvilket gør telefonen langsommere."</string>
+ <string name="permlab_foregroundService" msgid="3310786367649133115">"kør tjeneste i forgrunden"</string>
+ <string name="permdesc_foregroundService" msgid="6471634326171344622">"Tillad, at appen anvender tjenester i forgrunden."</string>
<string name="permlab_getPackageSize" msgid="7472921768357981986">"måle appens lagerplads"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"Tillader, at en app kan hente sin kode, data og cachestørrelser"</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"ændre systemindstillinger"</string>
@@ -419,10 +419,8 @@
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Tillader, at appen kan få adgang til telefonfunktionerne på enheden. Med denne tilladelse kan appen fastslå telefonnummeret og enheds-id\'erne, hvorvidt et opkald er aktivt samt det eksterne nummer, der oprettes forbindelse til via et opkald."</string>
<string name="permlab_manageOwnCalls" msgid="1503034913274622244">"dirigere opkald gennem systemet"</string>
<string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Tillader appen at dirigere sine opkald gennem systemet for at forbedre opkaldsoplevelsen."</string>
- <!-- no translation found for permlab_acceptHandover (2661534649736022409) -->
- <skip />
- <!-- no translation found for permdesc_acceptHandovers (4570660484220539698) -->
- <skip />
+ <string name="permlab_acceptHandover" msgid="2661534649736022409">"fortsætte et opkald fra en anden app"</string>
+ <string name="permdesc_acceptHandovers" msgid="4570660484220539698">"Tillader, at appen fortsætter et opkald, der blev startet i en anden app."</string>
<string name="permlab_readPhoneNumbers" msgid="6108163940932852440">"læse telefonnumre"</string>
<string name="permdesc_readPhoneNumbers" msgid="8559488833662272354">"Tillader, at appen får adgang til telefonnumrene på denne enhed."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"afholde tabletcomputeren fra at gå i dvale"</string>
@@ -497,11 +495,12 @@
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingeraftrykket kan ikke gemmes. Fjern et eksisterende fingeraftryk."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Registrering af fingeraftryk fik timeout. Prøv igen."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Fingeraftrykshandlingen blev annulleret."</string>
- <!-- no translation found for fingerprint_error_user_canceled (7999639584615291494) -->
- <skip />
+ <string name="fingerprint_error_user_canceled" msgid="7999639584615291494">"Fingeraftrykshandlingen blev annulleret af brugeren."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Du har prøvet for mange gange. Prøv igen senere."</string>
<string name="fingerprint_error_lockout_permanent" msgid="5033251797919508137">"Du har brugt for mange forsøg. Fingeraftrykslæseren er deaktiveret."</string>
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Prøv igen."</string>
+ <string name="fingerprint_error_no_fingerprints" msgid="7654382120628334248">"Der er ikke registreret nogen fingeraftryk."</string>
+ <string name="fingerprint_error_hw_not_present" msgid="5729436878065119329">"Denne enhed har ingen fingeraftrykslæser"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Fingeraftryk <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -1000,12 +999,9 @@
<string name="browse" msgid="1245903488306147205">"Åbn"</string>
<string name="sms" msgid="4560537514610063430">"Besked"</string>
<string name="add_contact" msgid="7867066569670597203">"Tilføj"</string>
- <!-- no translation found for view_calendar (979609872939597838) -->
- <skip />
- <!-- no translation found for add_calendar_event (1953664627192056206) -->
- <skip />
- <!-- no translation found for view_flight (7691640491425680214) -->
- <skip />
+ <string name="view_calendar" msgid="979609872939597838">"Se"</string>
+ <string name="add_calendar_event" msgid="1953664627192056206">"Planlæg"</string>
+ <string name="view_flight" msgid="7691640491425680214">"Spor"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Der er snart ikke mere lagerplads"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Nogle systemfunktioner virker måske ikke"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Der er ikke nok ledig lagerplads til systemet. Sørg for, at du har 250 MB ledig plads, og genstart."</string>
@@ -1131,8 +1127,7 @@
<item quantity="other">Åbne Wi-Fi-netværk er tilgængelige</item>
</plurals>
<string name="wifi_available_title" msgid="3817100557900599505">"Opret forbindelse til et åbent Wi-Fi-netværk"</string>
- <!-- no translation found for wifi_available_carrier_network_title (4527932626916527897) -->
- <skip />
+ <string name="wifi_available_carrier_network_title" msgid="4527932626916527897">"Opret forbindelse til dit mobilselskabs Wi‑Fi-netværk"</string>
<string name="wifi_available_title_connecting" msgid="1557292688310330032">"Opretter forbindelse til et åbent Wi‑Fi-netværk"</string>
<string name="wifi_available_title_connected" msgid="7542672851522241548">"Forbundet til Wi-Fi-netværket"</string>
<string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Der kan ikke oprettes forbindelse til Wi-Fi-netværket"</string>
@@ -1216,13 +1211,15 @@
<string name="no_permissions" msgid="7283357728219338112">"Der kræves ingen tilladelser"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"dette kan koste dig penge"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB oplader denne enhed"</string>
- <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB, der leverer strøm til den tilsluttede enhed"</string>
- <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB til filoverførsel"</string>
- <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB til billedoverførsel"</string>
- <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB til MIDI"</string>
- <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Tilsluttet et USB-ekstraudstyr"</string>
+ <string name="usb_charging_notification_title" msgid="1595122345358177163">"Enheden oplades via USB"</string>
+ <string name="usb_supplying_notification_title" msgid="4631045789893086181">"Den tilsluttede enhed oplades via USB"</string>
+ <string name="usb_mtp_notification_title" msgid="4238227258391151029">"Filoverførsel via USB er slået til"</string>
+ <string name="usb_ptp_notification_title" msgid="5425857879922006878">"PTP via USB er slået til"</string>
+ <string name="usb_tether_notification_title" msgid="3716143122035802501">"Netdeling via USB er slået til"</string>
+ <string name="usb_midi_notification_title" msgid="5356040379749154805">"MIDI via USB er slået til"</string>
+ <string name="usb_accessory_notification_title" msgid="1899977434994900306">"Tilstanden USB-tilbehør er slået til"</string>
<string name="usb_notification_message" msgid="3370903770828407960">"Tryk for at se flere muligheder."</string>
+ <string name="usb_power_notification_message" msgid="4647527153291917218">"Den tilsluttede enhed oplades. Tryk for at få flere valgmuligheder."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="3529881374464628084">"Der blev registreret et analogt lydtilbehør"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="6309553946441565215">"Den tilsluttede enhed er ikke kompatibel med denne telefon. Tryk for at få flere oplysninger."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-fejlretning er tilsluttet"</string>
@@ -1524,7 +1521,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%2$d</xliff:g> yderligere mislykkede forsøg til vil du blive bedt om at låse din telefon op ved hjælp af en e-mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Fjern"</string>
- <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Vil du skrue højere op end det anbefalede lydstyrkeniveau?\n\nDu kan skade hørelsen ved at lytte til meget højt musik over længere tid."</string>
+ <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Vil du skrue højere op end det anbefalede lydstyrkeniveau?\n\nDu kan skade hørelsen ved at lytte til meget høj musik over længere tid."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="8404780875025725199">"Vil du bruge genvejen til Hjælpefunktioner?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Når genvejen er slået til, kan du starte en hjælpefunktion ved at trykke på begge lydstyrkeknapper i tre sekunder.\n\n Nuværende hjælpefunktion:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Du kan skifte funktion i Indstillinger &gt; Hjælpefunktioner."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Deaktiver genvej"</string>
@@ -1661,9 +1658,6 @@
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> – arbejde"</string>
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. <xliff:g id="LABEL">%1$s</xliff:g> til arbejde"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. <xliff:g id="LABEL">%1$s</xliff:g> til arbejde"</string>
- <string name="lock_to_app_toast" msgid="6820571533009838261">"Hvis du vil frigøre dette skærmbillede, skal du trykke på knapperne Tilbage og Oversigt og holde fingrene nede"</string>
- <string name="lock_to_app_start" msgid="6643342070839862795">"Skærmen blev fastgjort"</string>
- <string name="lock_to_app_exit" msgid="8598219838213787430">"Skærmen blev frigjort"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Bed om pinkode inden frigørelse"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Bed om oplåsningsmønster ved deaktivering"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Bed om adgangskode inden frigørelse"</string>
@@ -1757,15 +1751,11 @@
<string name="language_picker_section_all" msgid="3097279199511617537">"Alle sprog"</string>
<string name="region_picker_section_all" msgid="8966316787153001779">"Alle områder"</string>
<string name="locale_search_menu" msgid="2560710726687249178">"Søg"</string>
- <!-- no translation found for work_mode_off_title (1118691887588435530) -->
- <skip />
- <!-- no translation found for work_mode_off_message (5130856710614337649) -->
- <skip />
+ <string name="work_mode_off_title" msgid="1118691887588435530">"Skal arbejdsprofilen slås til?"</string>
+ <string name="work_mode_off_message" msgid="5130856710614337649">"Dine arbejdsapps, underretninger, data og andre funktioner til din arbejdsprofil deaktiveres"</string>
<string name="work_mode_turn_on" msgid="2062544985670564875">"Slå til"</string>
- <!-- no translation found for deprecated_target_sdk_message (1449696506742572767) -->
- <skip />
- <!-- no translation found for deprecated_target_sdk_app_store (5032340500368495077) -->
- <skip />
+ <string name="deprecated_target_sdk_message" msgid="1449696506742572767">"Denne app er lavet til en ældre version af Android og fungerer muligvis ikke korrekt. Prøv at søge efter opdateringer, eller kontakt udvikleren."</string>
+ <string name="deprecated_target_sdk_app_store" msgid="5032340500368495077">"Søg efter opdatering"</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Du har nye beskeder"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Åbn sms-appen for at se beskeden"</string>
<string name="user_encrypted_title" msgid="9054897468831672082">"Nogle funktioner er begrænsede"</string>
@@ -1832,17 +1822,14 @@
<string name="mmcc_illegal_me" msgid="1950705155760872972">"Telefon er ikke tilladt for tale"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Pop op-vindue"</string>
<string name="slice_more_content" msgid="8504342889413274608">"<xliff:g id="NUMBER">%1$d</xliff:g> mere"</string>
- <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Denne genvej kræver den nyeste app"</string>
+ <string name="shortcut_restored_on_lower_version" msgid="4860853725206702336">"Appversionen er nedgraderet, eller også er den ikke kompatibel med denne genvej"</string>
<string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Genvejen kunne ikke gendannes, da appen ikke understøtter backup og gendannelse"</string>
<string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Genvejen kunne ikke gendannes på grund af uoverensstemmelse i appsignatur"</string>
<string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Genvejen kunne ikke gendannes"</string>
<string name="shortcut_disabled_reason_unknown" msgid="5276016910284687075">"Genvejen er deaktiveret"</string>
- <!-- no translation found for harmful_app_warning_uninstall (4837672735619532931) -->
- <skip />
- <!-- no translation found for harmful_app_warning_open_anyway (596432803680914321) -->
- <skip />
- <!-- no translation found for harmful_app_warning_title (8982527462829423432) -->
- <skip />
+ <string name="harmful_app_warning_uninstall" msgid="4837672735619532931">"AFINSTALLER"</string>
+ <string name="harmful_app_warning_open_anyway" msgid="596432803680914321">"ÅBN ALLIGEVEL"</string>
+ <string name="harmful_app_warning_title" msgid="8982527462829423432">"Der er registreret en skadelig app"</string>
<string name="slices_permission_request" msgid="8484943441501672932">"<xliff:g id="APP_0">%1$s</xliff:g> anmoder om tilladelse til at vise eksempler fra <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7867478911006447565">"Rediger"</string>
</resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 24363267cf50..1b3e1316b7af 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -264,10 +264,8 @@
<string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
<string name="safeMode" msgid="2788228061547930246">"Modu segurua"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistema"</string>
- <!-- no translation found for user_owner_label (8836124313744349203) -->
- <skip />
- <!-- no translation found for managed_profile_label (8947929265267690522) -->
- <skip />
+ <string name="user_owner_label" msgid="8836124313744349203">"Aldatu profil pertsonalera"</string>
+ <string name="managed_profile_label" msgid="8947929265267690522">"Aldatu laneko profilera"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktuak"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"atzitu kontaktuak"</string>
<string name="permgrouprequest_contacts" msgid="1601591667800538208">"Baimendu kontaktuak atzitzea &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; aplikazioari"</string>
@@ -357,6 +355,8 @@
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Beren zati batzuk memoria modu iraunkorrean ezartzeko baimena ematen die aplikazioei. Horrela, beste aplikazioek erabilgarri duten memoria murritz daiteke eta tableta motel daiteke."</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Beren zati batzuk memorian modu iraunkorrean aktibo uztea baimentzen die aplikazioei. Horrela, beste aplikazioek memoria gutxiago izan lezakete erabilgarri eta telebistak motelago funtziona lezake."</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Beren zati batzuk memoria modu iraunkorrean ezartzeko baimena ematen die aplikazioei. Horrela, beste aplikazioek erabilgarri duten memoria murritz daiteke eta telefonoa motel daiteke."</string>
+ <string name="permlab_foregroundService" msgid="3310786367649133115">"Exekutatu zerbitzuak aurreko planoan"</string>
+ <string name="permdesc_foregroundService" msgid="6471634326171344622">"Aurreko planoko zerbitzuak erabiltzea baimentzen dio aplikazioari."</string>
<string name="permlab_getPackageSize" msgid="7472921768357981986">"neurtu aplikazioen biltegiratze-tokia"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"Bere kodea, datuak eta cache-tamainak eskuratzea baimentzen die aplikazioei."</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"aldatu sistemaren ezarpenak"</string>
@@ -419,10 +419,8 @@
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Gailuaren telefono-eginbideak atzitzeko baimena ematen die aplikazioei. Baimen horrek aplikazioari telefono-zenbakia eta gailu IDak zein diren, deirik aktibo dagoen eta deia zer zenbakirekin konektatuta dagoen zehazteko baimena ematen die aplikazioei."</string>
<string name="permlab_manageOwnCalls" msgid="1503034913274622244">"bideratu deiak sistemaren bidez"</string>
<string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Deiak sistemaren bidez bideratzea baimentzen die aplikazioei, deien zerbitzua ahal bezain ona izan dadin."</string>
- <!-- no translation found for permlab_acceptHandover (2661534649736022409) -->
- <skip />
- <!-- no translation found for permdesc_acceptHandovers (4570660484220539698) -->
- <skip />
+ <string name="permlab_acceptHandover" msgid="2661534649736022409">"Jarraitu beste aplikazio batean hasitako deia"</string>
+ <string name="permdesc_acceptHandovers" msgid="4570660484220539698">"Beste aplikazio batean hasitako dei bat jarraitzea baimentzen dio aplikazioari."</string>
<string name="permlab_readPhoneNumbers" msgid="6108163940932852440">"irakurri telefono-zenbakiak"</string>
<string name="permdesc_readPhoneNumbers" msgid="8559488833662272354">"Gailuaren telefono-zenbakiak atzitzea baimentzen die aplikazioei."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"eragotzi tableta inaktibo ezartzea"</string>
@@ -497,11 +495,12 @@
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Ezin da gorde hatz-marka digitala. Kendu lehendik gordeta duzunetako bat."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Hatz-marka digitalak prozesatzeko denbora-muga gainditu da. Saiatu berriro."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Hatz-markaren eragiketa bertan behera utzi da."</string>
- <!-- no translation found for fingerprint_error_user_canceled (7999639584615291494) -->
- <skip />
+ <string name="fingerprint_error_user_canceled" msgid="7999639584615291494">"Erabiltzaileak bertan behera utzi du hatz-marka bidezko eragiketa."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Saiakera gehiegi egin dituzu. Saiatu berriro geroago."</string>
<string name="fingerprint_error_lockout_permanent" msgid="5033251797919508137">"Saiakera gehiegi egin dituzu. Desgaitu egin da hatz-marken sentsorea."</string>
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Saiatu berriro."</string>
+ <string name="fingerprint_error_no_fingerprints" msgid="7654382120628334248">"Ez da erregistratu hatz-markarik."</string>
+ <string name="fingerprint_error_hw_not_present" msgid="5729436878065119329">"Gailu honek ez du hatz-marken sentsorerik"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"<xliff:g id="FINGERID">%d</xliff:g> hatza"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -1000,12 +999,9 @@
<string name="browse" msgid="1245903488306147205">"Ireki"</string>
<string name="sms" msgid="4560537514610063430">"Bidali mezua"</string>
<string name="add_contact" msgid="7867066569670597203">"Gehitu"</string>
- <!-- no translation found for view_calendar (979609872939597838) -->
- <skip />
- <!-- no translation found for add_calendar_event (1953664627192056206) -->
- <skip />
- <!-- no translation found for view_flight (7691640491425680214) -->
- <skip />
+ <string name="view_calendar" msgid="979609872939597838">"Ikusi"</string>
+ <string name="add_calendar_event" msgid="1953664627192056206">"Antolatu"</string>
+ <string name="view_flight" msgid="7691640491425680214">"Egin jarraipena"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Memoria betetzen ari da"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Sistemaren funtzio batzuek ez dute agian funtzionatuko"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sisteman ez dago behar adina memoria. Ziurtatu gutxienez 250 MB erabilgarri dituzula eta, ondoren, berrabiarazi gailua."</string>
@@ -1131,8 +1127,7 @@
<item quantity="one">Wi-Fi sare irekia erabilgarri</item>
</plurals>
<string name="wifi_available_title" msgid="3817100557900599505">"Konektatu Wi‑Fi sare irekira"</string>
- <!-- no translation found for wifi_available_carrier_network_title (4527932626916527897) -->
- <skip />
+ <string name="wifi_available_carrier_network_title" msgid="4527932626916527897">"Konektatu operadorearen Wi‑Fi sarera"</string>
<string name="wifi_available_title_connecting" msgid="1557292688310330032">"Wi‑Fi sare irekira konektatzen"</string>
<string name="wifi_available_title_connected" msgid="7542672851522241548">"Wi‑Fi sare irekira konektatuta"</string>
<string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Ezin izan da konektatu Wi‑Fi sare irekira"</string>
@@ -1217,13 +1212,15 @@
<string name="no_permissions" msgid="7283357728219338112">"Ez da baimenik behar"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"dirua kosta dakizuke"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Ados"</string>
- <string name="usb_charging_notification_title" msgid="6895185153353640787">"Gailua USB bidez ari da kargatzen"</string>
- <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Konektatutako gailua USB bidez jasotzen ari da energia"</string>
- <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Fitxategiak transferitzeko USBa"</string>
- <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Argazkiak transferitzeko USBa"</string>
- <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI modurako USBa"</string>
- <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB osagarri batera konektatuta"</string>
+ <string name="usb_charging_notification_title" msgid="1595122345358177163">"Gailua USB bidez kargatzen"</string>
+ <string name="usb_supplying_notification_title" msgid="4631045789893086181">"Konektatutako gailua USB bidez kargatzen ari da"</string>
+ <string name="usb_mtp_notification_title" msgid="4238227258391151029">"Aktibatuta dago USB bidezko fitxategi-transferentzia"</string>
+ <string name="usb_ptp_notification_title" msgid="5425857879922006878">"Aktibatuta dago USB bidezko PTP modua"</string>
+ <string name="usb_tether_notification_title" msgid="3716143122035802501">"Aktibatuta dago USB bidez konexioa partekatzeko aukera"</string>
+ <string name="usb_midi_notification_title" msgid="5356040379749154805">"Aktibatuta dago USB bidezko MIDI modua"</string>
+ <string name="usb_accessory_notification_title" msgid="1899977434994900306">"Aktibatuta dago USB osagarriaren modua"</string>
<string name="usb_notification_message" msgid="3370903770828407960">"Sakatu aukera gehiago ikusteko."</string>
+ <string name="usb_power_notification_message" msgid="4647527153291917218">"Konektatutako gailua kargatzen ari da. Sakatu aukera gehiago ikusteko."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="3529881374464628084">"Audio-osagarri analogiko bat hauteman da"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="6309553946441565215">"Erantsitako gailua ez da telefono honekin bateragarria. Sakatu informazio gehiago lortzeko."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB arazketa konektatuta"</string>
@@ -1662,9 +1659,6 @@
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Laneko <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Laneko 2. <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Laneko 3. <xliff:g id="LABEL">%1$s</xliff:g>"</string>
- <string name="lock_to_app_toast" msgid="6820571533009838261">"Pantailari aingura kentzeko, eduki sakatuta Atzera eta Ikuspegi orokorra botoiak"</string>
- <string name="lock_to_app_start" msgid="6643342070839862795">"Pantaila ainguratu da"</string>
- <string name="lock_to_app_exit" msgid="8598219838213787430">"Aingura kendu zaio pantailari"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Eskatu PIN kodea aingura kendu aurretik"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Eskatu desblokeatzeko eredua aingura kendu aurretik"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Eskatu pasahitza aingura kendu aurretik"</string>
@@ -1758,15 +1752,11 @@
<string name="language_picker_section_all" msgid="3097279199511617537">"Hizkuntza guztiak"</string>
<string name="region_picker_section_all" msgid="8966316787153001779">"Lurralde guztiak"</string>
<string name="locale_search_menu" msgid="2560710726687249178">"Bilaketa"</string>
- <!-- no translation found for work_mode_off_title (1118691887588435530) -->
- <skip />
- <!-- no translation found for work_mode_off_message (5130856710614337649) -->
- <skip />
+ <string name="work_mode_off_title" msgid="1118691887588435530">"Laneko profila aktibatu?"</string>
+ <string name="work_mode_off_message" msgid="5130856710614337649">"Laneko aplikazioak, jakinarazpenak, datuak eta laneko profileko bestelako eginbideak aktibatuko dira"</string>
<string name="work_mode_turn_on" msgid="2062544985670564875">"Aktibatu"</string>
- <!-- no translation found for deprecated_target_sdk_message (1449696506742572767) -->
- <skip />
- <!-- no translation found for deprecated_target_sdk_app_store (5032340500368495077) -->
- <skip />
+ <string name="deprecated_target_sdk_message" msgid="1449696506742572767">"Aplikazioa Android-en bertsio zaharrago baterako sortu zenez, baliteke behar bezala ez funtzionatzea. Bilatu eguneratzerik baden, edo jarri garatzailearekin harremanetan."</string>
+ <string name="deprecated_target_sdk_app_store" msgid="5032340500368495077">"Bilatu eguneratzeak"</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Mezu berriak dituzu"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Mezuak ikusteko, ireki SMS mezuen aplikazioa"</string>
<string name="user_encrypted_title" msgid="9054897468831672082">"Funtzioak mugatuta egon litezke"</string>
@@ -1833,17 +1823,14 @@
<string name="mmcc_illegal_me" msgid="1950705155760872972">"Telefonoa ezin da erabili ahotsa erabiltzeko"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Leiho gainerakorra"</string>
<string name="slice_more_content" msgid="8504342889413274608">"Beste <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
- <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Aplikazioaren bertsio berriena behar da lasterbideak funtziona dezan"</string>
+ <string name="shortcut_restored_on_lower_version" msgid="4860853725206702336">"Aplikazioaren bertsio zaharrago batera aldatu da, edo aplikazioa ez da lasterbide honekin bateragarria"</string>
<string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Ezin izan da leheneratu lasterbidea aplikazioak ez duelako onartzen babeskopiak egiteko eta leheneratzeko aukera"</string>
<string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Ezin izan da leheneratu lasterbidea aplikazioaren sinadurak ez datozelako bat"</string>
<string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Ezin izan da leheneratu lasterbidea"</string>
<string name="shortcut_disabled_reason_unknown" msgid="5276016910284687075">"Desgaituta dago lasterbidea"</string>
- <!-- no translation found for harmful_app_warning_uninstall (4837672735619532931) -->
- <skip />
- <!-- no translation found for harmful_app_warning_open_anyway (596432803680914321) -->
- <skip />
- <!-- no translation found for harmful_app_warning_title (8982527462829423432) -->
- <skip />
+ <string name="harmful_app_warning_uninstall" msgid="4837672735619532931">"DESINSTALATU"</string>
+ <string name="harmful_app_warning_open_anyway" msgid="596432803680914321">"IREKI, HALA ERE"</string>
+ <string name="harmful_app_warning_title" msgid="8982527462829423432">"Aplikazio kaltegarri bat hauteman da"</string>
<string name="slices_permission_request" msgid="8484943441501672932">"<xliff:g id="APP_0">%1$s</xliff:g> aplikazioak <xliff:g id="APP_2">%2$s</xliff:g> aplikazioaren zatiak erakutsi nahi ditu"</string>
<string name="screenshot_edit" msgid="7867478911006447565">"Editatu"</string>
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 2891b8ca28f7..ade233cd8cf1 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -355,6 +355,8 @@
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Permet à l\'application de rendre certains de ces composants persistants dans la mémoire. Cette autorisation peut limiter la mémoire disponible pour d\'autres applications et ralentir la tablette."</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Permet à l\'application de placer certaines de ses parties en permanence dans la mémoire. Cela peut limiter la mémoire disponible pour les autres applications et ralentir le téléviseur."</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Permet à l\'application de rendre certains de ces composants persistants dans la mémoire. Cette autorisation peut limiter la mémoire disponible pour d\'autres applications et ralentir le téléphone."</string>
+ <string name="permlab_foregroundService" msgid="3310786367649133115">"exécuter le service en premier plan"</string>
+ <string name="permdesc_foregroundService" msgid="6471634326171344622">"Permet à l\'application d\'utiliser les services en premier plan."</string>
<string name="permlab_getPackageSize" msgid="7472921768357981986">"évaluer l\'espace de stockage de l\'application"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"Permet à l\'application de récupérer la taille de son code, de ses données et de sa mémoire cache."</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"modifier les paramètres du système"</string>
@@ -497,10 +499,8 @@
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Trop de tentatives. Veuillez réessayer plus tard."</string>
<string name="fingerprint_error_lockout_permanent" msgid="5033251797919508137">"Trop de tentatives. Capteur d\'empreintes digitales désactivé."</string>
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Réessayer."</string>
- <!-- no translation found for fingerprint_error_no_fingerprints (7654382120628334248) -->
- <skip />
- <!-- no translation found for fingerprint_error_hw_not_present (5729436878065119329) -->
- <skip />
+ <string name="fingerprint_error_no_fingerprints" msgid="7654382120628334248">"Aucune empreinte digitale enregistrée."</string>
+ <string name="fingerprint_error_hw_not_present" msgid="5729436878065119329">"Cet appareil ne possède pas de capteur d\'empreintes digitales"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Doigt <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -1211,23 +1211,15 @@
<string name="no_permissions" msgid="7283357728219338112">"Aucune autorisation requise"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"cela peut engendrer des frais"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_charging_notification_title (1595122345358177163) -->
- <skip />
- <!-- no translation found for usb_supplying_notification_title (4631045789893086181) -->
- <skip />
- <!-- no translation found for usb_mtp_notification_title (4238227258391151029) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (5425857879922006878) -->
- <skip />
- <!-- no translation found for usb_tether_notification_title (3716143122035802501) -->
- <skip />
- <!-- no translation found for usb_midi_notification_title (5356040379749154805) -->
- <skip />
- <!-- no translation found for usb_accessory_notification_title (1899977434994900306) -->
- <skip />
+ <string name="usb_charging_notification_title" msgid="1595122345358177163">"Chargement de cet appareil par USB"</string>
+ <string name="usb_supplying_notification_title" msgid="4631045789893086181">"Chargement de l\'appareil connecté par USB"</string>
+ <string name="usb_mtp_notification_title" msgid="4238227258391151029">"Transfert de fichiers USB activé"</string>
+ <string name="usb_ptp_notification_title" msgid="5425857879922006878">"Mode PTP par USB activé"</string>
+ <string name="usb_tether_notification_title" msgid="3716143122035802501">"Partage de connexion USB activé"</string>
+ <string name="usb_midi_notification_title" msgid="5356040379749154805">"Mode MIDI par USB activé"</string>
+ <string name="usb_accessory_notification_title" msgid="1899977434994900306">"Mode accessoire USB activé"</string>
<string name="usb_notification_message" msgid="3370903770828407960">"Touchez pour afficher plus d\'options."</string>
- <!-- no translation found for usb_power_notification_message (4647527153291917218) -->
- <skip />
+ <string name="usb_power_notification_message" msgid="4647527153291917218">"Chargement de l\'appareil connecté. Touchez l\'écran pour afficher plus d\'options."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="3529881374464628084">"Un accessoire audio analogique a été détecté"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="6309553946441565215">"L\'appareil connecté n\'est pas compatible avec ce téléphone. Touchez ici en savoir plus."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB activé"</string>
@@ -1830,8 +1822,7 @@
<string name="mmcc_illegal_me" msgid="1950705155760872972">"Ce téléphone n\'est pas autorisé pour la voix"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Fenêtre contextuelle"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
- <!-- no translation found for shortcut_restored_on_lower_version (4860853725206702336) -->
- <skip />
+ <string name="shortcut_restored_on_lower_version" msgid="4860853725206702336">"La version de l\'application a été rétrogradée ou n\'est pas compatible avec ce raccourci"</string>
<string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Impossible de restaurer le raccourci, car l\'application ne prend pas en charge la sauvegarde et la restauration"</string>
<string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Impossible de restaurer le raccourci en raison d\'une erreur de correspondance des signature d\'applications"</string>
<string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Impossible de restaurer le raccourci"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 0b7b7d09bd4d..efee73679259 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -264,10 +264,8 @@
<string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
<string name="safeMode" msgid="2788228061547930246">"Անվտանգ ռեժիմ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android համակարգ"</string>
- <!-- no translation found for user_owner_label (8836124313744349203) -->
- <skip />
- <!-- no translation found for managed_profile_label (8947929265267690522) -->
- <skip />
+ <string name="user_owner_label" msgid="8836124313744349203">"Բացել անձնական պրոֆիլը"</string>
+ <string name="managed_profile_label" msgid="8947929265267690522">"Բացել աշխատանքային պրոֆիլը"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Կոնտակտներ"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"օգտագործել ձեր կոնտակտները"</string>
<string name="permgrouprequest_contacts" msgid="1601591667800538208">"Թույլ տալ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; հավելվածին օգտագործել ձեր կոնտակտները"</string>
@@ -357,6 +355,8 @@
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Թույլ է տալիս հավելվածին մնայուն դարձնել իր մասերը հիշողության մեջ: Սա կարող է սահմանափակել այլ հավելվածներին հասանելի հիշողությունը` դանդաղեցնելով պլանշետի աշխատանքը:"</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Թույլ է տալիս հավելվածին պահել իր տարրերը հիշողության մեջ: Սա կարող է սահմանափակել այլ հավելվածների համար հատկացված հիշողությունը և դանդաղեցնել հեռուստացույցի աշխատանքը:"</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Թույլ է տալիս հավելվածին մնայուն դարձնել իր մասերը հիշողության մեջ: Սա կարող է սահմանափակել այլ հավելվածներին հասանելի հիշողությունը` դանդաղեցնելով հեռախոսի աշխատանքը:"</string>
+ <string name="permlab_foregroundService" msgid="3310786367649133115">"աշխատեցնել ակտիվ ծառայությունները"</string>
+ <string name="permdesc_foregroundService" msgid="6471634326171344622">"Թույլ է տալիս հավելվածին օգտագործել ակտիվ ծառայությունները:"</string>
<string name="permlab_getPackageSize" msgid="7472921768357981986">"չափել հավելվածի պահոցի տարածքը"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"Թույլ է տալիս հավելվածին առբերել իր կոդը, տվյալները և քեշի չափերը"</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"փոփոխել համակարգի կարգավորումները"</string>
@@ -419,10 +419,8 @@
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Թույլ է տալիս հավելվածին օգտագործել սարքի հեռախոսային գործիքները: Այս թույլտվությունը հավելվածին հնարավորություն է տալիս որոշել հեռախոսահամարը և սարքի ID-ները, արդյոք զանգը ակտիվ է և միացված զանգի հեռակա հեռախոսահամարը:"</string>
<string name="permlab_manageOwnCalls" msgid="1503034913274622244">"զանգերն ուղարկել համակարգի միջոցով"</string>
<string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Հավելվածին թույլ է տալիս իր զանգերն ուղարկել համակարգի միջոցով՝ կապի որակը բարձրացնելու նպատակով։"</string>
- <!-- no translation found for permlab_acceptHandover (2661534649736022409) -->
- <skip />
- <!-- no translation found for permdesc_acceptHandovers (4570660484220539698) -->
- <skip />
+ <string name="permlab_acceptHandover" msgid="2661534649736022409">"շարունակել զանգը այլ հավելվածի միջոցով"</string>
+ <string name="permdesc_acceptHandovers" msgid="4570660484220539698">"Թույլ է տալիս հավելվածին շարունակել մեկ այլ հավելվածի միջոցով սկսած զանգը:"</string>
<string name="permlab_readPhoneNumbers" msgid="6108163940932852440">"օգտագործել հեռախոսահամարները"</string>
<string name="permdesc_readPhoneNumbers" msgid="8559488833662272354">"Հավելվածին թույլ է տալիս օգտագործել սարքի հեռախոսահամարները:"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"զերծ պահել պլանշետը քնելուց"</string>
@@ -497,11 +495,12 @@
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Հնարավոր չէ պահել մատնահետքը: Հեռացրեք առկա մատնահետքը:"</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Մատնահետքի գրանցման ժամանակը սպառվել է: Փորձեք նորից:"</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Իսկորոշումը մատնահետքի միջոցով չեղարկվեց:"</string>
- <!-- no translation found for fingerprint_error_user_canceled (7999639584615291494) -->
- <skip />
+ <string name="fingerprint_error_user_canceled" msgid="7999639584615291494">"Մատնահետքով նույնականացման գործողությունը չեղարկվել է օգտատիրոջ կողմից:"</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Չափից շատ փորձ եք կատարել: Փորձեք նորից քիչ հետո:"</string>
<string name="fingerprint_error_lockout_permanent" msgid="5033251797919508137">"Չափից շատ փորձ եք կատարել: Մատնահետքերի սկաներն անջատվել է:"</string>
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Փորձեք նորից:"</string>
+ <string name="fingerprint_error_no_fingerprints" msgid="7654382120628334248">"Գրանցված մատնահետք չկա:"</string>
+ <string name="fingerprint_error_hw_not_present" msgid="5729436878065119329">"Սարքը չունի մատնահետքի սկաներ"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Մատնահետք <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -1000,12 +999,9 @@
<string name="browse" msgid="1245903488306147205">"Բացել"</string>
<string name="sms" msgid="4560537514610063430">"SMS գրել"</string>
<string name="add_contact" msgid="7867066569670597203">"Ավելացնել"</string>
- <!-- no translation found for view_calendar (979609872939597838) -->
- <skip />
- <!-- no translation found for add_calendar_event (1953664627192056206) -->
- <skip />
- <!-- no translation found for view_flight (7691640491425680214) -->
- <skip />
+ <string name="view_calendar" msgid="979609872939597838">"Դիտել"</string>
+ <string name="add_calendar_event" msgid="1953664627192056206">"Ժամանակացույց"</string>
+ <string name="view_flight" msgid="7691640491425680214">"Հետագծել"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Հիշողությունը սպառվում է"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Որոշ գործառույթներ կարող են չաշխատել"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Համակարգի համար բավարար հիշողություն չկա: Համոզվեք, որ ունեք 250ՄԲ ազատ տարածություն և վերագործարկեք:"</string>
@@ -1131,8 +1127,7 @@
<item quantity="other">Հասանելի են չպաշտպանված Wi-Fi ցանցեր</item>
</plurals>
<string name="wifi_available_title" msgid="3817100557900599505">"Միացեք բաց Wi‑Fi ցանցին"</string>
- <!-- no translation found for wifi_available_carrier_network_title (4527932626916527897) -->
- <skip />
+ <string name="wifi_available_carrier_network_title" msgid="4527932626916527897">"Միացեք օպերատորի Wi‑Fi ցանցին"</string>
<string name="wifi_available_title_connecting" msgid="1557292688310330032">"Միացում բաց Wi‑Fi ցանցին"</string>
<string name="wifi_available_title_connected" msgid="7542672851522241548">"Միացել է Wi‑Fi ցանցին"</string>
<string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Չհաջողվեց միանալ Wi‑Fi ցանցին"</string>
@@ -1216,13 +1211,15 @@
<string name="no_permissions" msgid="7283357728219338112">"Թույլտվություններ չեն պահանջվում"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"Սա կարող է գումար պահանջել"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Հաստատել"</string>
- <string name="usb_charging_notification_title" msgid="6895185153353640787">"Սարքի լիցքավորում USB լարի միջոցով"</string>
- <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Հոսանքի մատակարարում կցված սարքերին USB լարի միջոցով"</string>
- <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Ֆայլերի փոխանցման USB"</string>
- <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Լուսանկարների փոխանցման USB"</string>
- <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI-ի USB"</string>
- <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Կապակցված է USB լրասարքի"</string>
+ <string name="usb_charging_notification_title" msgid="1595122345358177163">"Սարքի լիցքավորում USB-ի միջոցով"</string>
+ <string name="usb_supplying_notification_title" msgid="4631045789893086181">"Միացված սարքի լիցքավորում USB-ի միջոցով"</string>
+ <string name="usb_mtp_notification_title" msgid="4238227258391151029">"Ֆայլերի փոխանցումը USB-ի միջոցով միացավ"</string>
+ <string name="usb_ptp_notification_title" msgid="5425857879922006878">"PTP ռեժիմը USB-ի միջոցով միացավ"</string>
+ <string name="usb_tether_notification_title" msgid="3716143122035802501">"USB մոդեմի ռեժիմը միացավ"</string>
+ <string name="usb_midi_notification_title" msgid="5356040379749154805">"MIDI ռեժիմը USB-ի միջոցով միացավ"</string>
+ <string name="usb_accessory_notification_title" msgid="1899977434994900306">"USB լրասարքի ռեժիմը միացավ"</string>
<string name="usb_notification_message" msgid="3370903770828407960">"Հպեք՝ լրացուցիչ ընտրանքների համար:"</string>
+ <string name="usb_power_notification_message" msgid="4647527153291917218">"Միացված սարքի լիցքավորում: Հպեք՝ ավելի շատ ընտրանքների համար:"</string>
<string name="usb_unsupported_audio_accessory_title" msgid="3529881374464628084">"Հայտնաբերված է անալոգային աուդիո լրասարք"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="6309553946441565215">"Միացված սարքը համատեղելի չէ այս հեռախոսի հետ: Հպեք` ավելին իմանալու համար:"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB վրիպազերծումը միացված է"</string>
@@ -1458,7 +1455,7 @@
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Գրասալիկ"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Հեռուստացույց"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Հեռախոս"</string>
- <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Համակցված բարձրախոսներ"</string>
+ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Դոկ-կայանի բարձրախոսներ"</string>
<string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Ականջակալներ"</string>
<string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
@@ -1661,9 +1658,6 @@
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Աշխատանքային <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2-րդ աշխատանք <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3-րդ աշխատանք <xliff:g id="LABEL">%1$s</xliff:g>"</string>
- <string name="lock_to_app_toast" msgid="6820571533009838261">"Այս էկրանն ապամրացնելու համար հպեք և պահեք Հետ և Համատեսք կոճակները"</string>
- <string name="lock_to_app_start" msgid="6643342070839862795">"Էկրանն ամրացված է"</string>
- <string name="lock_to_app_exit" msgid="8598219838213787430">"Էկրանն ապամրացված է"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ապաամրացնելուց առաջ հարցնել PIN-կոդը"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Ապաամրացնելուց առաջ հարցնել ապակողպող նախշը"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Ապաամրացնելուց առաջ հարցնել գաղտնաբառը"</string>
@@ -1757,15 +1751,11 @@
<string name="language_picker_section_all" msgid="3097279199511617537">"Բոլոր լեզուները"</string>
<string name="region_picker_section_all" msgid="8966316787153001779">"Բոլոր տարածաշրջանները"</string>
<string name="locale_search_menu" msgid="2560710726687249178">"Որոնում"</string>
- <!-- no translation found for work_mode_off_title (1118691887588435530) -->
- <skip />
- <!-- no translation found for work_mode_off_message (5130856710614337649) -->
- <skip />
+ <string name="work_mode_off_title" msgid="1118691887588435530">"Միացնե՞լ աշխատանքային պրոֆիլը"</string>
+ <string name="work_mode_off_message" msgid="5130856710614337649">"Ձեր աշխատանքային հավելվածները, ծանուցումները, տվյալները և աշխատանքային պրոֆիլի մյուս գործառույթները կմիանան"</string>
<string name="work_mode_turn_on" msgid="2062544985670564875">"Միացնել"</string>
- <!-- no translation found for deprecated_target_sdk_message (1449696506742572767) -->
- <skip />
- <!-- no translation found for deprecated_target_sdk_app_store (5032340500368495077) -->
- <skip />
+ <string name="deprecated_target_sdk_message" msgid="1449696506742572767">"Այս հավելվածը ստեղծվել է Android-ի ավելի հին տարբերակի համար և կարող է պատշաճ չաշխատել: Ստուգեք թարմացումների առկայությունը կամ դիմեք մշակողին:"</string>
+ <string name="deprecated_target_sdk_app_store" msgid="5032340500368495077">"Ստուգել նոր տարբերակի առկայությունը"</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Դուք ունեք նոր հաղորդագրություններ"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Դիտելու համար բացել SMS հավելվածը"</string>
<string name="user_encrypted_title" msgid="9054897468831672082">"Որոշ գործառույթներ կարող են սահմանափակված լինել"</string>
@@ -1832,17 +1822,14 @@
<string name="mmcc_illegal_me" msgid="1950705155760872972">"Այս հեռախոսով չեք կարող զանգել"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Հայտնվող պատուհան"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
- <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Այս դյուրանցման համար անհրաժեշտ է հավելվածի վերջին տարբերակը"</string>
+ <string name="shortcut_restored_on_lower_version" msgid="4860853725206702336">"Սա հավելվածի ավելի հին տարբերակն է կամ համատեղելի չէ այս դյուրանցման հետ"</string>
<string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Չհաջողվեց վերականգնել դյուրանցումը, քանի որ հավելվածում չի աջակցվում պահուստավորման և վերականգնման գործառույթը"</string>
<string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Չհաջողվեց վերականգնել դյուրանցումը, քանի որ հավելվածների ստորագրությունները տարբեր են"</string>
<string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Չհաջողվեց վերականգնել դյուրանցումը"</string>
<string name="shortcut_disabled_reason_unknown" msgid="5276016910284687075">"Դյուրանցումն անջատված է"</string>
- <!-- no translation found for harmful_app_warning_uninstall (4837672735619532931) -->
- <skip />
- <!-- no translation found for harmful_app_warning_open_anyway (596432803680914321) -->
- <skip />
- <!-- no translation found for harmful_app_warning_title (8982527462829423432) -->
- <skip />
+ <string name="harmful_app_warning_uninstall" msgid="4837672735619532931">"ՀԵՌԱՑՆԵԼ"</string>
+ <string name="harmful_app_warning_open_anyway" msgid="596432803680914321">"ԲԱՑԵԼ"</string>
+ <string name="harmful_app_warning_title" msgid="8982527462829423432">"Հայտնաբերվել է վնասաբեր հավելված"</string>
<string name="slices_permission_request" msgid="8484943441501672932">"<xliff:g id="APP_0">%1$s</xliff:g> հավելվածն ուզում է ցուցադրել հատվածներ <xliff:g id="APP_2">%2$s</xliff:g> հավելվածից"</string>
<string name="screenshot_edit" msgid="7867478911006447565">"Փոփոխել"</string>
</resources>
diff --git a/core/res/res/values-mcc302-mnc220/config.xml b/core/res/res/values-mcc302-mnc220/config.xml
index 9a3d7361118c..8774334f11be 100644
--- a/core/res/res/values-mcc302-mnc220/config.xml
+++ b/core/res/res/values-mcc302-mnc220/config.xml
@@ -36,7 +36,7 @@
<!-- Values for GPS configuration (Telus) -->
<string-array translatable="false" name="config_gpsParameters">
- <item>SUPL_HOST=supl.telusmobility.com</item>
+ <item>SUPL_HOST=supl.google.com</item>
<item>SUPL_PORT=7275</item>
<item>SUPL_VER=0x20000</item>
<item>SUPL_MODE=1</item>
diff --git a/core/res/res/values-mcc302-mnc221/config.xml b/core/res/res/values-mcc302-mnc221/config.xml
index 007fd045ced7..05896b18cfb8 100644
--- a/core/res/res/values-mcc302-mnc221/config.xml
+++ b/core/res/res/values-mcc302-mnc221/config.xml
@@ -34,7 +34,7 @@
<!-- Values for GPS configuration (Telus) -->
<string-array translatable="false" name="config_gpsParameters">
- <item>SUPL_HOST=supl.telusmobility.com</item>
+ <item>SUPL_HOST=supl.google.com</item>
<item>SUPL_PORT=7275</item>
<item>SUPL_VER=0x20000</item>
<item>SUPL_MODE=1</item>
diff --git a/core/res/res/values-television/dimens.xml b/core/res/res/values-television/dimens.xml
index 4c25225dd50c..aa5625124f29 100644
--- a/core/res/res/values-television/dimens.xml
+++ b/core/res/res/values-television/dimens.xml
@@ -20,4 +20,8 @@
<item type="dimen" format="float" name="ambient_shadow_alpha">0.15</item>
<item type="dimen" format="float" name="spot_shadow_alpha">0.3</item>
+ <!-- Max width/height of the autofill data set picker as a fraction of the screen width/height -->
+ <dimen name="autofill_dataset_picker_max_width">60%</dimen>
+ <dimen name="autofill_dataset_picker_max_height">70%</dimen>
+
</resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index c9076ca57fe6..5ac81d5faa3c 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -355,6 +355,8 @@
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Ilovaga o‘zining komponentlarini xotirada doimiy saqlashga ruxsat beradi. Bu mavjud xotirani cheklashi va planshetni sekin ishlashiga sabab bo‘lishi mumkin."</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Ilovaga o‘zining muayyan qismlarining xotiraning turg‘un qismiga aylantirish huquqini beradi. Bunda, boshqa ilovalar uchun xotiradan ajratilgan joy cheklanib, televizorning ishlashi sekinlashishi mumkin."</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Ilovaga o‘zining komponentlarini xotirada doimiy saqlashga ruxsat beradi. Bu mavjud xotirani cheklashi va telefonni sekin ishlashiga sabab bo‘lishi mumkin."</string>
+ <string name="permlab_foregroundService" msgid="3310786367649133115">"faol xizmatlarni ishga tushirish"</string>
+ <string name="permdesc_foregroundService" msgid="6471634326171344622">"Ilovaga faol xizmatlardan foydalanishga ruxsat beradi."</string>
<string name="permlab_getPackageSize" msgid="7472921768357981986">"ilovalar egallagan xotira joyini hisoblash"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"Ilova o‘zining kodi, ma’lumotlari va kesh o‘lchami to‘g‘risidagi ma’lumotlarni olishi mumkin"</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"tizim sozlamalarini o‘zgartirish"</string>
@@ -497,10 +499,8 @@
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Urinishlar soni ko‘payib ketdi. Keyinroq qayta urinib ko‘ring."</string>
<string name="fingerprint_error_lockout_permanent" msgid="5033251797919508137">"Urinishlar soni ko‘payib ketdi. Barmoq izi skaneri bloklandi."</string>
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Qayta urinib ko‘ring."</string>
- <!-- no translation found for fingerprint_error_no_fingerprints (7654382120628334248) -->
- <skip />
- <!-- no translation found for fingerprint_error_hw_not_present (5729436878065119329) -->
- <skip />
+ <string name="fingerprint_error_no_fingerprints" msgid="7654382120628334248">"Hech qanday barmoq izi qayd qilinmagan."</string>
+ <string name="fingerprint_error_hw_not_present" msgid="5729436878065119329">"Bu qurilmada barmoq izi skaneri yo‘q"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Barmoq izi <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -1212,23 +1212,15 @@
<string name="no_permissions" msgid="7283357728219338112">"Hech qanday ruxsat talab qilinmaydi"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"buning uchun sizdan haq olinishi mumkin"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_charging_notification_title (1595122345358177163) -->
- <skip />
- <!-- no translation found for usb_supplying_notification_title (4631045789893086181) -->
- <skip />
- <!-- no translation found for usb_mtp_notification_title (4238227258391151029) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (5425857879922006878) -->
- <skip />
- <!-- no translation found for usb_tether_notification_title (3716143122035802501) -->
- <skip />
- <!-- no translation found for usb_midi_notification_title (5356040379749154805) -->
- <skip />
- <!-- no translation found for usb_accessory_notification_title (1899977434994900306) -->
- <skip />
+ <string name="usb_charging_notification_title" msgid="1595122345358177163">"Bu qurilma USB orqali quvvatlanmoqda"</string>
+ <string name="usb_supplying_notification_title" msgid="4631045789893086181">"USB orqali ulangan qurilma quvvatlanmoqda"</string>
+ <string name="usb_mtp_notification_title" msgid="4238227258391151029">"USB orqali fayl uzatish yoqildi"</string>
+ <string name="usb_ptp_notification_title" msgid="5425857879922006878">"USB orqali PTP rejimi yoqildi"</string>
+ <string name="usb_tether_notification_title" msgid="3716143122035802501">"USB modem rejimi yoqildi"</string>
+ <string name="usb_midi_notification_title" msgid="5356040379749154805">"USB orqali MIDI rejimi yoqildi"</string>
+ <string name="usb_accessory_notification_title" msgid="1899977434994900306">"USB qurilma ulandi"</string>
<string name="usb_notification_message" msgid="3370903770828407960">"Boshqa parametrlarini ko‘rish uchun bosing."</string>
- <!-- no translation found for usb_power_notification_message (4647527153291917218) -->
- <skip />
+ <string name="usb_power_notification_message" msgid="4647527153291917218">"Ulangan qurilma quvvatlanmoqda. Boshqa parametrlar uchun bosing."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="3529881374464628084">"Analogli audio uskuna aniqlandi"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="6309553946441565215">"Biriktirilgan qurilma mazkur telefon bilan mos emas. Batafsil axborot olish uchun bu yerga bosing."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB orqali nosozliklarni tuzatish"</string>
@@ -1831,8 +1823,7 @@
<string name="mmcc_illegal_me" msgid="1950705155760872972">"Ovoz uchun telefon taqiqlangan"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Qalqib chiquvchi oyna"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
- <!-- no translation found for shortcut_restored_on_lower_version (4860853725206702336) -->
- <skip />
+ <string name="shortcut_restored_on_lower_version" msgid="4860853725206702336">"Ilova versiyasi eski yoki bu yorliq bilan mos emas"</string>
<string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Ilovada zaxiralash va tiklash ishlamagani uchun yorliq tiklanmadi"</string>
<string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Ilova imzosi mos kelmagani uchun yorliq tiklanmadi"</string>
<string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Yorliq tiklanmadi"</string>
diff --git a/core/res/res/values-watch/colors_device_defaults.xml b/core/res/res/values-watch/colors_device_defaults.xml
index 654e92cf62f7..6ffd6e697361 100644
--- a/core/res/res/values-watch/colors_device_defaults.xml
+++ b/core/res/res/values-watch/colors_device_defaults.xml
@@ -14,89 +14,103 @@
limitations under the License.
-->
-<!-- Colors specific to DeviceDefault themes. These are mostly pass-throughs to enable
- overlaying new theme colors. -->
+<!-- Colors specific to Theme.DeviceDefault on watches, as specified via themes_device_default.xml
+ Note: These colors specifically proide a darker, high-contrast UI that is suitable for
+ wearables with respect to 'glanceability'. OEM customization is supported within this set. -->
<resources>
-
- <!--
- primary_device_default_dark
- > from values/colors_material/primary_material_dark
- > from values/colors_material/material_grey_900
- = #ff212121
- ! replaced with custom color #33ffffff
- -->
- <color name="primary_device_default_dark">#33ffffff</color>
- <!--
- primary_dark_device_default_dark
- > from values/colors_material/primary_dark_material_dark
- = @color/black
- -->
- <color name="primary_dark_device_default_dark">@color/black</color>
<!--
accent_device_default_dark
> from values/colors_material/accent_material_dark
> from values/colors_material/material_deep_teal_200
= #ff80cbc4
! replaced with custom color #5E97F6
+ ! OEMS can customize as per specification
-->
<color name="accent_device_default_dark">#5E97F6</color>
+
+ <!--
+ foreground_device_default_dark
+ - introduced to avoid coupling to foreground_material_dark
+ - colorForeground typically falls through Theme.DeviceDefault to Theme.Material
+ ! fixed as white for optimal glanceability/contrast
+ ! OEMs should not customize
+ -->
+ <color name="foreground_device_default_dark">@color/white</color>
+
<!--
background_device_default_dark
> from values/colors_material/background_material_dark
> from values/colors_material/material_grey_850
= #ff303030
- ! replaced with custom color #232E33
+ ! replaced with custom color #000000
+ ! OEMs can customized as per specification
+ (derived from accent color, constrained by brightness)
-->
- <color name="background_device_default_dark">#232E33</color>
+ <color name="background_device_default_dark">#000000</color>
+
<!--
background_floating_device_default_dark
> from values/colors_material/background_floating_material_dark
> from values/colors_material/material_grey_800
= #ff424242
- ! replaced with custom color #3E5059
+ ! replaced with custom color #1D2E4D
+ (derived from accent color, constrained by brightness)
-->
- <color name="background_floating_device_default_dark">#3E5059</color>
+ <color name="background_floating_device_default_dark">#1D2E4D</color>
<!--
- background_cache_hint_selector_device_default
- - note that this is based off of colors/background_cache_hint_selector_device_default
- xml drawable
- - uses ?attr/colorBackground and transparency to draw
- - no color customization required here
+ primary_device_default_dark
+ > from values/colors_material/primary_material_dark
+ > from values/colors_material/material_grey_900
+ = #ff212121
+ ! replaced with custom color #808080
+ ! OEMs can customize as per specification
+ (derived from background color + foreground @ 50% opacity)
-->
+ <color name="primary_device_default_dark">#808080</color>
<!--
- button_normal_device_default_dark
- - uses ?attr/disabledAlpha and button_material_dark to draw
- - cloned to watch_btn_default.xml drawable
- (btn_default_material_dark & button_material_dark - see
- values-watch/colors_material.xml)
+ primary_dark_device_default_dark
+ > from values/colors_material/primary_dark_material_dark
+ = @color/black
+ ! replaced with custom color #333333
+ ! OEMS can customize as per specification
+ (derived from background color + foreground @ 20% opacity)
-->
- <color name="button_normal_device_default_dark">@color/btn_default_material_dark</color>
-
- <!-- Use the same value as for accent_device_default_dark but start with #99,
- i.e. 60% opacity -->
- <color name="accent_device_default_dark_60_percent_opacity">#995E97f6</color>
+ <color name="primary_dark_device_default_dark">#333333</color>
<!--
- foreground_device_default_dark
- - introduced to avoid coupling to foreground_material_dark
- - colorForeground typically falls through Theme.DeviceDefault to Theme.Material
+ button_normal_device_default_dark
+ - uses ?attr/disabledAlpha and ?attr/colorPrimaryDark to draw state list
+ (used as colorButtonNormal attribute in theme)
+ - see color-watch/btn_watch_default_dark.xml
-->
- <color name="foreground_device_default_dark">@color/white</color>
+ <color name="button_normal_device_default_dark">@color/btn_watch_default_dark</color>
<!--
error_color_device_default_dark
- - introduced to avoid coupling to error_color_material (also #F4511E)
+ - introduced to avoid coupling to error_color_mtterial (also #F4511E)
- colorError typically falls through Theme.DeviceDefault to Theme.Material
+ ! OEMs can customize as per specification
-->
<color name="error_color_device_default_dark">#F4511E</color>
+ <!-- no customization required/suggested below this point -->
+
+ <!--
+ background_cache_hint_selector_device_default
+ - note that this is based off of colors/background_cache_hint_selector_device_default
+ xml drawable
+ - uses ?attr/colorBackground and transparency to draw
+ - no color customization required here
+ -->
+
<!-- deprecated for Wear
these overrides exist only for compatibility with existing
WTS theme test heuristics, based on the previous modifications
to the material theme, they should not be used for customization
as they are not exposed via publicly accessible attributes -->
+ <color name="accent_device_default_dark_60_percent_opacity">#995E97f6</color>
<color name="accent_device_default_700">#5385DB</color>
<color name="accent_device_default_light">#75A4F5</color>
<color name="accent_device_default_50">#93B7F5</color>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 005d07dc008a..d26567e9a3f5 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -7918,6 +7918,10 @@
android.content.pm.PackageInfo#getLongVersionCode()} for the target package.
-->
<attr name="maxLongVersionCode" format="string" />
+ <!-- The resource id of view that contains the URL bar of the HTML page being loaded.
+ Typically used when compatibility mode is used in a browser.
+ -->
+ <attr name="urlBarResourceId" format="string" />
</declare-styleable>
<!-- =============================== -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 287f29615e2b..32fe2b2a72d8 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2558,6 +2558,9 @@
<!-- Package name of base package whose resources will be overlaid. -->
<attr name="targetPackage" />
+ <!-- Category of the resource overlay. -->
+ <attr name="category" format="string"/>
+
<!-- Load order of overlay package. -->
<attr name="priority" />
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index e80f16c466b3..6e8134b079b2 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -78,9 +78,9 @@
<item name="secondary_content_alpha_material_dark" format="float" type="dimen">.7</item>
<item name="secondary_content_alpha_material_light" format="float" type="dimen">0.54</item>
- <item name="highlight_alpha_material_light" format="float" type="dimen">0.16</item>
- <item name="highlight_alpha_material_dark" format="float" type="dimen">0.16</item>
- <item name="highlight_alpha_material_colored" format="float" type="dimen">0.16</item>
+ <item name="highlight_alpha_material_light" format="float" type="dimen">0.10</item>
+ <item name="highlight_alpha_material_dark" format="float" type="dimen">0.10</item>
+ <item name="highlight_alpha_material_colored" format="float" type="dimen">0.10</item>
<!-- Primary & accent colors -->
<eat-comment />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d2194ba25029..091129858736 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -999,7 +999,7 @@
<integer name="config_shortPressOnSleepBehavior">0</integer>
<!-- Time to wait while a button is pressed before triggering a very long press. -->
- <integer name="config_veryLongPressTimeout">6000</integer>
+ <integer name="config_veryLongPressTimeout">3500</integer>
<!-- Package name for default keyguard appwidget [DO NOT TRANSLATE] -->
<string name="widget_default_package_name" translatable="false"></string>
@@ -2328,6 +2328,10 @@
<string name="config_customVpnAlwaysOnDisconnectedDialogComponent" translatable="false"
>com.android.vpndialogs/com.android.vpndialogs.AlwaysOnDisconnectedDialog</string>
+ <!-- Name of the dialog that is used to install the carrier app when the SIM is inserted -->
+ <string name="config_carrierAppInstallDialogComponent" translatable="false"
+ >com.android.simappdialog/com.android.simappdialog.InstallCarrierAppActivity</string>
+
<!-- Apps that are authorized to access shared accounts, overridden by product overlays -->
<string name="config_appsAuthorizedForSharedAccounts" translatable="false">;com.android.settings;</string>
@@ -2913,8 +2917,8 @@
<item name="config_pictureInPictureAspectRatioLimitForMinSize" format="float" type="dimen">1.777778</item>
<!-- The default gravity for the picture-in-picture window.
- Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT -->
- <integer name="config_defaultPictureInPictureGravity">0x55</integer>
+ Currently, this maps to Gravity.TOP | Gravity.RIGHT -->
+ <integer name="config_defaultPictureInPictureGravity">0x35</integer>
<!-- The minimum aspect ratio (width/height) that is supported for picture-in-picture. Any
ratio smaller than this is considered too tall and thin to be usable. Currently, this
@@ -3311,4 +3315,10 @@
<!-- IWLAN network service package name to bind to by default. If none is specified in an overlay, an
empty string is passed in -->
<string name="config_wlan_network_service_package" translatable="false"></string>
+
+ <!-- Wear devices: Controls the radios affected by Activity Mode. -->
+ <string-array name="config_wearActivityModeRadios">
+ <item>"wifi"</item>
+ </string-array>
+
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 0411c6ed8833..cfaab6ac2eec 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -626,7 +626,8 @@
<dimen name="messaging_avatar_size">@dimen/notification_right_icon_size</dimen>
<!-- Max width/height of the autofill data set picker as a fraction of the screen width/height -->
- <dimen name="autofill_dataset_picker_max_size">90%</dimen>
+ <dimen name="autofill_dataset_picker_max_width">90%</dimen>
+ <dimen name="autofill_dataset_picker_max_height">90%</dimen>
<!-- Max height of the the autofill save custom subtitle as a fraction of the screen width/height -->
<dimen name="autofill_save_custom_subtitle_max_height">20%</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 93f22f25d7d3..82fefef5fef6 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2869,6 +2869,7 @@
<public name="outlineSpotShadowColor" />
<public name="outlineAmbientShadowColor" />
<public name="maxLongVersionCode" />
+ <public name="urlBarResourceId" />
</public-group>
<public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ec81df7b89e2..837113d4845e 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -182,6 +182,8 @@
<string name="notification_channel_voice_mail">Voicemail messages</string>
<!-- Telephony notification channel name for a channel containing wifi calling status notifications. -->
<string name="notification_channel_wfc">Wi-Fi calling</string>
+ <!-- Telephony notification channel name for a channel containing SIM notifications -->
+ <string name="notification_channel_sim">SIM status</string>
<!-- Displayed to tell the user that peer changed TTY mode -->
<string name="peerTtyModeFull">Peer requested TTY Mode FULL</string>
@@ -547,7 +549,7 @@
<string name="global_action_voice_assist">Voice Assist</string>
<!-- label for item that locks the phone and enforces that it can't be unlocked without strong authentication. [CHAR LIMIT=15] -->
- <string name="global_action_lockdown">Enter lockdown</string>
+ <string name="global_action_lockdown">Lockdown</string>
<!-- Text to use when the number in a notification info is too large
(greater than status_bar_notification_info_maxnum, defined in
@@ -2169,6 +2171,9 @@
<!-- Text to show in the auto complete drop down list on a text view when the WebView can auto fill the entire form but the user has not configured an AutoFill profile [CHAR-LIMIT=19] -->
<string name="setup_autofill">Set up Autofill</string>
+ <!-- Title of fullscreen autofill window [CHAR-LIMIT=80] -->
+ <string name="autofill_window_title">Autofill</string>
+
<!-- String used to separate FirstName and LastName when writing out a local name
e.g. John<separator>Smith [CHAR-LIMIT=NONE]-->
<string name="autofill_address_name_separator">\u0020</string>
@@ -3194,10 +3199,12 @@
<!-- See SIM_ADDED_DIALOG. This is the button of that dialog. -->
<string name="sim_restart_button">Restart</string>
<!-- See Carrier_App_Dialog. This is the message of that dialog. -->
- <string name="carrier_app_dialog_message">To get your new SIM working properly, you\'ll need to install and open an app from your carrier.</string>
- <!-- See Carrier_App_Dialog. This is the button of that dialog. -->
- <string name="carrier_app_dialog_button">GET THE APP</string>
- <string name="carrier_app_dialog_not_now">NOT NOW</string>
+ <string name="install_carrier_app_notification_title">Activate mobile service</string>
+ <string name="install_carrier_app_notification_text">
+ Download the carrier app to activate your new SIM
+ </string>
+ <!-- See Carrier_App_Notification. This is the button of that dialog. -->
+ <string name="install_carrier_app_notification_button">Download app</string>
<!-- See carrier_app_notification. This is the headline. -->
<string name="carrier_app_notification_title">New SIM inserted</string>
<string name="carrier_app_notification_text">Tap to set it up</string>
@@ -4854,4 +4861,11 @@
<!-- Notification action for editing a screenshot (drawing on it, cropping it, etc) -->
<string name="screenshot_edit">Edit</string>
+
+ <!-- Title for the notification channel notifying user of settings system changes (i.e. Do Not Disturb has changed). [CHAR LIMIT=NONE] -->
+ <string name="notification_channel_system_changes">System changes</string>
+ <!-- Title of notification indicating do not disturb settings have changed when upgrading to P -->
+ <string name="zen_upgrade_notification_title">Do Not Disturb has changed</string>
+ <!-- Content of notification indicating users can tap on the notification to go to dnd behavior settings -->
+ <string name="zen_upgrade_notification_content">Tap to check your behavior settings for interruptions</string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ca698ef2b55b..9995642ba455 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -574,6 +574,7 @@
<java-symbol type="string" name="notification_channel_sms" />
<java-symbol type="string" name="notification_channel_voice_mail" />
<java-symbol type="string" name="notification_channel_wfc" />
+ <java-symbol type="string" name="notification_channel_sim" />
<java-symbol type="string" name="SetupCallDefault" />
<java-symbol type="string" name="accept" />
<java-symbol type="string" name="activity_chooser_view_see_all" />
@@ -1383,6 +1384,7 @@
<java-symbol type="drawable" name="ic_sim_card_multi_24px_clr" />
<java-symbol type="drawable" name="ic_sim_card_multi_48px_clr" />
+ <java-symbol type="drawable" name="ic_signal_cellular_alt_24px" />
<java-symbol type="drawable" name="stat_notify_mmcc_indication_icn" />
<java-symbol type="drawable" name="autofilled_highlight"/>
@@ -1716,6 +1718,7 @@
<java-symbol type="string" name="bugreport_status" />
<java-symbol type="string" name="bugreport_title" />
<java-symbol type="string" name="faceunlock_multiple_failures" />
+ <java-symbol type="string" name="global_actions" />
<java-symbol type="string" name="global_action_power_off" />
<java-symbol type="string" name="global_action_restart" />
<java-symbol type="string" name="global_actions_airplane_mode_off_status" />
@@ -2071,6 +2074,7 @@
<java-symbol type="string" name="config_customAdbPublicKeyConfirmationSecondaryUserComponent" />
<java-symbol type="string" name="config_customVpnConfirmDialogComponent" />
<java-symbol type="string" name="config_customVpnAlwaysOnDisconnectedDialogComponent" />
+ <java-symbol type="string" name="config_carrierAppInstallDialogComponent" />
<java-symbol type="string" name="config_defaultNetworkScorerPackageName" />
<java-symbol type="string" name="config_persistentDataPackageName" />
@@ -2770,9 +2774,9 @@
<java-symbol type="array" name="resolver_target_actions_pin" />
<java-symbol type="array" name="resolver_target_actions_unpin" />
- <java-symbol type="string" name="carrier_app_dialog_message" />
- <java-symbol type="string" name="carrier_app_dialog_button" />
- <java-symbol type="string" name="carrier_app_dialog_not_now" />
+ <java-symbol type="string" name="install_carrier_app_notification_title" />
+ <java-symbol type="string" name="install_carrier_app_notification_text" />
+ <java-symbol type="string" name="install_carrier_app_notification_button" />
<java-symbol type="string" name="carrier_app_notification_title" />
<java-symbol type="string" name="carrier_app_notification_text" />
<java-symbol type="string" name="negative_duration" />
@@ -2986,6 +2990,8 @@
<!-- com.android.server.autofill -->
<java-symbol type="layout" name="autofill_save"/>
<java-symbol type="layout" name="autofill_dataset_picker"/>
+ <java-symbol type="layout" name="autofill_dataset_picker_fullscreen"/>
+ <java-symbol type="id" name="autofill_dataset_container"/>
<java-symbol type="id" name="autofill_dataset_list"/>
<java-symbol type="id" name="autofill_dataset_picker"/>
<java-symbol type="id" name="autofill" />
@@ -3014,7 +3020,8 @@
<java-symbol type="drawable" name="autofill_dataset_picker_background" />
<java-symbol type="style" name="AutofillDatasetPicker" />
<java-symbol type="style" name="AutofillSaveAnimation" />
- <java-symbol type="dimen" name="autofill_dataset_picker_max_size"/>
+ <java-symbol type="dimen" name="autofill_dataset_picker_max_width"/>
+ <java-symbol type="dimen" name="autofill_dataset_picker_max_height"/>
<java-symbol type="dimen" name="autofill_save_custom_subtitle_max_height"/>
<java-symbol type="dimen" name="autofill_save_icon_max_size"/>
@@ -3102,6 +3109,7 @@
<java-symbol type="string" name="notification_channel_retail_mode" />
<java-symbol type="string" name="notification_channel_usb" />
<java-symbol type="string" name="notification_channel_heavy_weight_app" />
+ <java-symbol type="string" name="notification_channel_system_changes" />
<java-symbol type="string" name="config_defaultAutofillService" />
<java-symbol type="string" name="config_defaultTextClassifierService" />
@@ -3254,4 +3262,11 @@
<java-symbol type="bool" name="config_keepRestrictedProfilesInBackground" />
<java-symbol type="array" name="config_ringtoneEffectUris" />
+
+ <!-- For Wear devices -->
+ <java-symbol type="array" name="config_wearActivityModeRadios" />
+
+ <java-symbol type="string" name="zen_upgrade_notification_title" />
+ <java-symbol type="string" name="zen_upgrade_notification_content" />
+
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 9c3d8ebfa505..eed0e463df99 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -41,58 +41,44 @@ please see themes_device_defaults.xml.
#Theme_Holo} or {@link #Theme_DeviceDefault}.</p>
-->
<style name="Theme">
-
<item name="isLightTheme">false</item>
+
<item name="colorForeground">@color/bright_foreground_dark</item>
<item name="colorForegroundInverse">@color/bright_foreground_dark_inverse</item>
<item name="colorBackground">@color/background_dark</item>
<item name="colorBackgroundFloating">?attr/colorBackground</item>
<item name="colorBackgroundCacheHint">?attr/colorBackground</item>
-
- <item name="colorPressedHighlight">@color/legacy_pressed_highlight</item>
- <item name="colorLongPressedHighlight">@color/legacy_long_pressed_highlight</item>
- <item name="colorFocusedHighlight">@color/legacy_selected_highlight</item>
- <item name="colorMultiSelectHighlight">@color/legacy_selected_highlight</item>
- <item name="colorActivatedHighlight">@color/legacy_selected_highlight</item>
-
- <item name="colorPrimaryDark">@color/legacy_primary_dark</item>
- <item name="colorPrimary">@color/legacy_primary</item>
- <item name="colorSecondary">?attr/colorPrimary</item>
- <item name="colorControlActivated">@color/legacy_control_activated</item>
- <item name="colorControlNormal">@color/legacy_control_normal</item>
- <item name="colorControlHighlight">@color/legacy_button_pressed</item>
- <item name="colorButtonNormal">@color/legacy_button_normal</item>
- <item name="colorEdgeEffect">?attr/colorPrimary</item>
- <item name="colorError">@color/red</item>
-
<item name="disabledAlpha">0.5</item>
+ <item name="primaryContentAlpha">@dimen/primary_content_alpha_material_dark</item>
+ <item name="secondaryContentAlpha">@dimen/secondary_content_alpha_material_dark</item>
<item name="backgroundDimAmount">0.6</item>
+ <item name="colorError">@color/red</item>
<!-- Text styles -->
<item name="textAppearance">@style/TextAppearance</item>
<item name="textAppearanceInverse">@style/TextAppearance.Inverse</item>
<item name="textColorPrimary">@color/primary_text_dark</item>
- <item name="textColorSecondary">@color/secondary_text_dark</item>
- <item name="textColorTertiary">@color/tertiary_text_dark</item>
<item name="textColorPrimaryInverse">@color/primary_text_light</item>
- <item name="textColorSecondaryInverse">@color/secondary_text_light</item>
- <item name="textColorTertiaryInverse">@color/tertiary_text_light</item>
<item name="textColorPrimaryActivated">@color/primary_text_dark</item>
- <item name="textColorSecondaryActivated">@color/secondary_text_dark</item>
<item name="textColorPrimaryDisableOnly">@color/primary_text_dark_disable_only</item>
<item name="textColorPrimaryInverseDisableOnly">@color/primary_text_light_disable_only</item>
+ <item name="textColorPrimaryInverseNoDisable">@color/primary_text_light_nodisable</item>
<item name="textColorPrimaryNoDisable">@color/primary_text_dark_nodisable</item>
+ <item name="textColorSecondary">@color/secondary_text_dark</item>
+ <item name="textColorSecondaryInverse">@color/secondary_text_light</item>
+ <item name="textColorSecondaryActivated">@color/secondary_text_dark</item>
<item name="textColorSecondaryNoDisable">@color/secondary_text_dark_nodisable</item>
- <item name="textColorPrimaryInverseNoDisable">@color/primary_text_light_nodisable</item>
<item name="textColorSecondaryInverseNoDisable">@color/secondary_text_light_nodisable</item>
+ <item name="textColorTertiary">@color/tertiary_text_dark</item>
+ <item name="textColorTertiaryInverse">@color/tertiary_text_light</item>
<item name="textColorHint">@color/hint_foreground_dark</item>
<item name="textColorHintInverse">@color/hint_foreground_light</item>
- <item name="textColorSearchUrl">@color/search_url_text</item>
<item name="textColorHighlight">@color/highlighted_text_dark</item>
<item name="textColorHighlightInverse">@color/highlighted_text_light</item>
<item name="textColorLink">@color/link_text_dark</item>
<item name="textColorLinkInverse">@color/link_text_light</item>
+ <item name="textColorSearchUrl">@color/search_url_text</item>
<item name="textColorAlertDialogListItem">@color/primary_text_light_disable_only</item>
<item name="textAppearanceLarge">@style/TextAppearance.Large</item>
@@ -120,14 +106,19 @@ please see themes_device_defaults.xml.
<item name="textAppearanceLargePopupMenu">@style/TextAppearance.Widget.PopupMenu.Large</item>
<item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Widget.PopupMenu.Small</item>
+ <item name="textAppearancePopupMenuHeader">@null</item>
<!-- Button styles -->
<item name="buttonStyle">@style/Widget.Button</item>
+
<item name="buttonStyleSmall">@style/Widget.Button.Small</item>
<item name="buttonStyleInset">@style/Widget.Button.Inset</item>
+
<item name="buttonStyleToggle">@style/Widget.Button.Toggle</item>
+ <item name="buttonCornerRadius">0dp</item>
<item name="switchStyle">@style/Widget.CompoundButton.Switch</item>
+ <item name="mediaRouteButtonStyle">@style/Widget.DeviceDefault.MediaRouteButton</item>
<item name="selectableItemBackground">@drawable/item_background</item>
<item name="selectableItemBackgroundBorderless">?attr/selectableItemBackground</item>
@@ -156,7 +147,6 @@ please see themes_device_defaults.xml.
<item name="listChoiceIndicatorMultiple">@drawable/btn_check</item>
<item name="listChoiceBackgroundIndicator">@drawable/list_selector_background</item>
-
<item name="activatedBackgroundIndicator">@drawable/activated_background</item>
<item name="listDividerAlertDialog">@drawable/divider_horizontal_bright</item>
@@ -215,6 +205,7 @@ please see themes_device_defaults.xml.
<item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title</item>
<item name="dialogTitleDecorLayout">@layout/dialog_title</item>
<item name="dialogPreferredPadding">@dimen/dialog_padding</item>
+ <item name="dialogCornerRadius">0dp</item>
<!-- AlertDialog attributes -->
<item name="alertDialogTheme">@style/Theme.Dialog.Alert</item>
@@ -239,6 +230,7 @@ please see themes_device_defaults.xml.
<item name="panelMenuIsCompact">false</item>
<item name="panelMenuListWidth">296dip</item>
+ <item name="panelMenuListTheme">@null</item>
<!-- Scrollbar attributes -->
<item name="scrollbarFadeDuration">250</item>
@@ -316,8 +308,9 @@ please see themes_device_defaults.xml.
<item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.QuickContactBadgeSmall.WindowLarge</item>
<item name="listPopupWindowStyle">@style/Widget.ListPopupWindow</item>
<item name="popupMenuStyle">@style/Widget.PopupMenu</item>
+ <item name="popupTheme">@null</item>
+ <item name="stackViewStyle">@null</item>
<item name="activityChooserViewStyle">@style/Widget.ActivityChooserView</item>
- <item name="mediaRouteButtonStyle">@style/Widget.DeviceDefault.MediaRouteButton</item>
<item name="fragmentBreadCrumbsStyle">@style/Widget.FragmentBreadCrumbs</item>
<item name="contextPopupMenuStyle">?attr/popupMenuStyle</item>
@@ -432,6 +425,22 @@ please see themes_device_defaults.xml.
<item name="fastScrollOverlayPosition">floating</item>
<item name="fastScrollTextColor">@color/primary_text_dark</item>
+
+ <item name="colorPressedHighlight">@color/legacy_pressed_highlight</item>
+ <item name="colorLongPressedHighlight">@color/legacy_long_pressed_highlight</item>
+ <item name="colorFocusedHighlight">@color/legacy_selected_highlight</item>
+ <item name="colorMultiSelectHighlight">@color/legacy_selected_highlight</item>
+ <item name="colorActivatedHighlight">@color/legacy_selected_highlight</item>
+
+ <item name="colorPrimaryDark">@color/legacy_primary_dark</item>
+ <item name="colorPrimary">@color/legacy_primary</item>
+ <item name="colorSecondary">?attr/colorPrimary</item>
+ <item name="colorControlActivated">@color/legacy_control_activated</item>
+ <item name="colorControlNormal">@color/legacy_control_normal</item>
+ <item name="colorControlHighlight">@color/legacy_button_pressed</item>
+ <item name="colorButtonNormal">@color/legacy_button_normal</item>
+ <item name="colorEdgeEffect">?attr/colorPrimary</item>
+
<!-- Accessibility focused drawable -->
<item name="accessibilityFocusedDrawable">@drawable/view_accessibility_focused</item>
@@ -451,8 +460,8 @@ please see themes_device_defaults.xml.
<item name="tooltipBackgroundColor">@color/tooltip_background_light</item>
<!-- Autofill: max width/height of the dataset picker as a fraction of screen size -->
- <item name="autofillDatasetPickerMaxWidth">@dimen/autofill_dataset_picker_max_size</item>
- <item name="autofillDatasetPickerMaxHeight">@dimen/autofill_dataset_picker_max_size</item>
+ <item name="autofillDatasetPickerMaxWidth">@dimen/autofill_dataset_picker_max_width</item>
+ <item name="autofillDatasetPickerMaxHeight">@dimen/autofill_dataset_picker_max_height</item>
<!-- Autofill: max height of custom save subtitle as a fraction of screen size -->
<item name="autofillSaveCustomSubtitleMaxHeight">@dimen/autofill_save_custom_subtitle_max_height</item>
diff --git a/core/res/res/values/themes_holo.xml b/core/res/res/values/themes_holo.xml
index 8f73479e95ac..3fe7c05c16e2 100644
--- a/core/res/res/values/themes_holo.xml
+++ b/core/res/res/values/themes_holo.xml
@@ -29,20 +29,9 @@ please see themes_device_defaults.xml.
===============================================================
-->
<resources>
- <!-- The default theme for apps on API level 10 and lower. This is the theme used for
- activities that have not explicitly set their own theme.
- <p>You can count on this being a dark
- background with light text on top, but should try to make no
- other assumptions about its appearance. In particular, the text
- inside of widgets using this theme may be completely different,
- with the widget container being a light color and the text on top
- of it a dark color.
- <p>If you're developing for API level 11 and higher, you should instead use {@link
- #Theme_Holo} or {@link #Theme_DeviceDefault}.</p>
- -->
<!-- Honeycomb holographic theme (dark version).
- <p>This is the default system theme for apps that target API level 11 - 13. Starting
+ <p>This is the default system theme for apps that target API level 11 - 20. Starting
with API level 14, the default system theme is supplied by {@link #Theme_DeviceDefault},
which might apply a different style on different devices. If you want to ensure that your
app consistently uses the Holo theme at all times, you must explicitly declare it in your
@@ -60,7 +49,9 @@ please see themes_device_defaults.xml.
TextAppearance.Holo.Widget.PopupMenu.Large}).
Specific resources used by Holo are named using the convention @type/foo_bar_baz_holo
with trailing _dark or _light specifiers if they are not shared between both light and
- dark versions of the theme. -->
+ dark versions of the theme.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo">
<item name="colorForeground">@color/bright_foreground_holo_dark</item>
<item name="colorForegroundInverse">@color/bright_foreground_inverse_holo_dark</item>
@@ -68,21 +59,10 @@ please see themes_device_defaults.xml.
<item name="colorBackgroundFloating">@color/background_holo_dark</item>
<item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_holo_dark</item>
<item name="disabledAlpha">0.5</item>
+ <item name="primaryContentAlpha">@dimen/primary_content_alpha_material_dark</item>
+ <item name="secondaryContentAlpha">@dimen/secondary_content_alpha_material_dark</item>
<item name="backgroundDimAmount">0.6</item>
-
- <item name="colorPressedHighlight">@color/holo_gray_light</item>
- <item name="colorLongPressedHighlight">@color/holo_gray_bright</item>
- <item name="colorFocusedHighlight">@color/holo_blue_dark</item>
- <item name="colorMultiSelectHighlight">@color/holo_green_light</item>
- <item name="colorActivatedHighlight">@color/holo_blue_dark</item>
-
- <item name="colorPrimaryDark">@color/holo_primary_dark</item>
- <item name="colorPrimary">@color/holo_primary</item>
- <item name="colorControlActivated">@color/holo_control_activated</item>
- <item name="colorControlNormal">@color/holo_control_normal</item>
- <item name="colorControlHighlight">@color/holo_button_pressed</item>
- <item name="colorButtonNormal">@color/holo_button_normal</item>
- <item name="colorEdgeEffect">?attr/colorPrimary</item>
+ <item name="colorError">@color/error_color_material_dark</item>
<!-- Text styles -->
<item name="textAppearance">@style/TextAppearance.Holo</item>
@@ -132,6 +112,7 @@ please see themes_device_defaults.xml.
<item name="textAppearanceLargePopupMenu">@style/TextAppearance.Holo.Widget.PopupMenu.Large</item>
<item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Holo.Widget.PopupMenu.Small</item>
+ <item name="textAppearancePopupMenuHeader">@null</item>
<item name="textEditSuggestionItemLayout">@layout/text_edit_suggestion_item</item>
<item name="textEditSuggestionContainerLayout">@layout/text_edit_suggestion_container</item>
@@ -144,6 +125,8 @@ please see themes_device_defaults.xml.
<item name="buttonStyleInset">@style/Widget.Holo.Button.Inset</item>
<item name="buttonStyleToggle">@style/Widget.Holo.Button.Toggle</item>
+ <item name="buttonCornerRadius">0dp</item>
+
<item name="switchStyle">@style/Widget.Holo.CompoundButton.Switch</item>
<item name="mediaRouteButtonStyle">@style/Widget.Holo.MediaRouteButton</item>
@@ -157,6 +140,7 @@ please see themes_device_defaults.xml.
<item name="listPreferredItemHeightSmall">48dip</item>
<item name="listPreferredItemHeightLarge">80dip</item>
<item name="dropdownListPreferredItemHeight">?attr/listPreferredItemHeightSmall</item>
+ <item name="textAppearanceListItem">?attr/textAppearanceLarge</item>
<item name="textAppearanceListItemSmall">?attr/textAppearanceMedium</item>
<item name="textAppearanceListItemSecondary">?attr/textAppearanceSmall</item>
<item name="listPreferredItemPaddingLeft">8dip</item>
@@ -212,6 +196,8 @@ please see themes_device_defaults.xml.
<item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_holo</item>
<item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_holo</item>
<item name="dialogTitleDecorLayout">@layout/dialog_title_holo</item>
+ <item name="dialogPreferredPadding">@dimen/dialog_padding</item>
+ <item name="dialogCornerRadius">0dp</item>
<!-- AlertDialog attributes -->
<item name="alertDialogTheme">@style/Theme.Holo.Dialog.Alert</item>
@@ -251,6 +237,9 @@ please see themes_device_defaults.xml.
<item name="textSelectHandleRight">@drawable/text_select_handle_right_material</item>
<item name="textSelectHandle">@drawable/text_select_handle_middle_material</item>
<item name="textSelectHandleWindowStyle">@style/Widget.Holo.TextSelectHandle</item>
+ <item name="textEditSuggestionItemLayout">@layout/text_edit_suggestion_item</item>
+ <item name="textEditSuggestionContainerLayout">@layout/text_edit_suggestion_container</item>
+ <item name="textEditSuggestionHighlightStyle">@style/TextAppearance.Holo.SuggestionHighlight</item>
<item name="textCursorDrawable">@drawable/text_cursor_holo_dark</item>
<!-- Widget styles -->
@@ -268,6 +257,7 @@ please see themes_device_defaults.xml.
<item name="gridViewStyle">@style/Widget.Holo.GridView</item>
<item name="imageButtonStyle">@style/Widget.Holo.ImageButton</item>
<item name="imageWellStyle">@style/Widget.Holo.ImageWell</item>
+ <item name="listMenuViewStyle">@null</item>
<item name="listViewStyle">@style/Widget.Holo.ListView</item>
<item name="listViewWhiteStyle">@style/Widget.Holo.ListView.White</item>
<item name="popupWindowStyle">@style/Widget.Holo.PopupWindow</item>
@@ -308,9 +298,11 @@ please see themes_device_defaults.xml.
<item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.Holo.QuickContactBadgeSmall.WindowLarge</item>
<item name="listPopupWindowStyle">@style/Widget.Holo.ListPopupWindow</item>
<item name="popupMenuStyle">@style/Widget.Holo.PopupMenu</item>
+ <item name="popupTheme">@null</item>
<item name="stackViewStyle">@style/Widget.Holo.StackView</item>
<item name="activityChooserViewStyle">@style/Widget.Holo.ActivityChooserView</item>
<item name="fragmentBreadCrumbsStyle">@style/Widget.Holo.FragmentBreadCrumbs</item>
+ <item name="contextPopupMenuStyle">?attr/popupMenuStyle</item>
<!-- Preference styles -->
<item name="preferenceScreenStyle">@style/Preference.Holo.PreferenceScreen</item>
@@ -327,8 +319,16 @@ please see themes_device_defaults.xml.
<item name="editTextPreferenceStyle">@style/Preference.Holo.DialogPreference.EditTextPreference</item>
<item name="ringtonePreferenceStyle">@style/Preference.Holo.RingtonePreference</item>
<item name="preferenceLayoutChild">@layout/preference_child_holo</item>
+ <item name="preferencePanelStyle">@null</item>
+ <item name="preferenceHeaderPanelStyle">@null</item>
+ <item name="preferenceListStyle">@null</item>
+ <item name="preferenceFragmentListStyle">@null</item>
+ <item name="preferenceFragmentPaddingSide">@null</item>
<item name="detailsElementBackground">@drawable/panel_bg_holo_dark</item>
+ <!-- PreferenceFrameLayout attributes -->
+ <item name="preferenceFrameLayoutStyle">@style/Widget.Holo.PreferenceFrameLayout</item>
+
<!-- Search widget styles -->
<item name="searchWidgetCorpusItemBackground">@color/search_widget_corpus_item_background</item>
@@ -348,9 +348,13 @@ please see themes_device_defaults.xml.
<item name="actionBarStyle">@style/Widget.Holo.ActionBar</item>
<item name="actionBarSize">@dimen/action_bar_default_height</item>
<item name="actionModePopupWindowStyle">@style/Widget.Holo.PopupWindow.ActionMode</item>
+ <item name="actionMenuTextAppearance">@null</item>
+ <item name="actionMenuTextColor">@null</item>
<item name="actionBarWidgetTheme">@null</item>
- <item name="actionBarPopupTheme">@null</item>
+ <item name="actionBarPopupTheme">?attr/popupTheme</item>
<item name="actionBarTheme">@null</item>
+ <item name="actionBarDivider">?attr/dividerVertical</item>
+ <item name="actionBarItemBackground">@null</item>
<item name="actionModeCutDrawable">@drawable/ic_menu_cut_holo_dark</item>
<item name="actionModeCopyDrawable">@drawable/ic_menu_copy_holo_dark</item>
@@ -360,6 +364,8 @@ please see themes_device_defaults.xml.
<item name="actionModeFindDrawable">@drawable/ic_menu_find_holo_dark</item>
<item name="actionModeWebSearchDrawable">@drawable/ic_menu_search_holo_dark</item>
+ <item name="toolbarStyle">@null</item>
+
<item name="dividerVertical">?attr/listDivider</item>
<item name="dividerHorizontal">?attr/listDivider</item>
<item name="buttonBarStyle">@style/Holo.ButtonBar</item>
@@ -397,13 +403,39 @@ please see themes_device_defaults.xml.
<item name="fastScrollTrackDrawable">@drawable/fastscroll_track_holo_dark</item>
<item name="fastScrollOverlayPosition">atThumb</item>
+
+ <item name="colorPrimaryDark">@color/holo_primary_dark</item>
+ <item name="colorPrimary">@color/holo_primary</item>
+ <item name="colorAccent">@color/holo_blue_dark</item>
+ <item name="colorEdgeEffect">?attr/colorPrimary</item>
+
+ <item name="colorControlNormal">@color/holo_control_normal</item>
+ <item name="colorControlActivated">@color/holo_control_activated</item>
+
+ <item name="colorControlHighlight">@color/holo_button_pressed</item>
+ <item name="colorButtonNormal">@color/holo_button_normal</item>
+ <item name="colorSwitchThumbNormal">@color/switch_thumb_material_light</item>
+
+ <!-- Tooltip popup properties -->
+ <item name="tooltipForegroundColor">@null</item>
+ <item name="tooltipBackgroundColor">@null</item>
+
+ <!-- Holo-only color attributes -->
+ <item name="colorPressedHighlight">@color/holo_gray_light</item>
+ <item name="colorLongPressedHighlight">@color/holo_gray_bright</item>
+ <item name="colorFocusedHighlight">@color/holo_blue_dark</item>
+ <item name="colorMultiSelectHighlight">@color/holo_green_light</item>
+ <item name="colorActivatedHighlight">@color/holo_blue_dark</item>
+
</style>
<!-- Honeycomb holographic theme (light version). The widgets in the
holographic theme are translucent on their brackground, so applications
must ensure that any background they use with this theme is itself
light; otherwise, it will be difficult to see the widgets. This
- UI style also includes a full action bar by default. -->
+ UI style also includes a full action bar by default.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Light" parent="Theme.Light">
<item name="colorForeground">@color/bright_foreground_holo_light</item>
<item name="colorForegroundInverse">@color/bright_foreground_inverse_holo_light</item>
@@ -411,46 +443,36 @@ please see themes_device_defaults.xml.
<item name="colorBackgroundFloating">@color/background_holo_light</item>
<item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_holo_light</item>
<item name="disabledAlpha">0.5</item>
+ <item name="primaryContentAlpha">@dimen/primary_content_alpha_material_dark</item>
+ <item name="secondaryContentAlpha">@dimen/secondary_content_alpha_material_dark</item>
<item name="backgroundDimAmount">0.6</item>
-
- <item name="colorPressedHighlight">@color/holo_gray_light</item>
- <item name="colorLongPressedHighlight">@color/holo_gray_bright</item>
- <item name="colorFocusedHighlight">@color/holo_blue_dark</item>
- <item name="colorMultiSelectHighlight">@color/holo_green_light</item>
- <item name="colorActivatedHighlight">@color/holo_blue_dark</item>
-
- <item name="colorPrimaryDark">@color/holo_light_primary_dark</item>
- <item name="colorPrimary">@color/holo_light_primary</item>
- <item name="colorControlActivated">@color/holo_light_control_activated</item>
- <item name="colorControlNormal">@color/holo_light_control_normal</item>
- <item name="colorControlHighlight">@color/holo_light_button_pressed</item>
- <item name="colorButtonNormal">@color/holo_light_button_normal</item>
+ <item name="colorError">@color/error_color_material_light</item>
<!-- Text styles -->
<item name="textAppearance">@style/TextAppearance.Holo.Light</item>
<item name="textAppearanceInverse">@style/TextAppearance.Holo.Light.Inverse</item>
<item name="textColorPrimary">@color/primary_text_holo_light</item>
- <item name="textColorSecondary">@color/secondary_text_holo_light</item>
- <item name="textColorTertiary">@color/tertiary_text_holo_light</item>
<item name="textColorPrimaryInverse">@color/primary_text_holo_dark</item>
- <item name="textColorSecondaryInverse">@color/secondary_text_holo_dark</item>
- <item name="textColorTertiaryInverse">@color/tertiary_text_holo_dark</item>
<item name="textColorPrimaryActivated">@color/primary_text_holo_light</item>
- <item name="textColorSecondaryActivated">@color/secondary_text_holo_light</item>
<item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_holo_light</item>
<item name="textColorPrimaryInverseDisableOnly">@color/primary_text_disable_only_holo_dark</item>
+ <item name="textColorPrimaryInverseNoDisable">@color/primary_text_nodisable_holo_dark</item>
<item name="textColorPrimaryNoDisable">@color/primary_text_nodisable_holo_light</item>
+ <item name="textColorSecondary">@color/secondary_text_holo_light</item>
+ <item name="textColorSecondaryInverse">@color/secondary_text_holo_dark</item>
+ <item name="textColorSecondaryActivated">@color/secondary_text_holo_light</item>
<item name="textColorSecondaryNoDisable">@color/secondary_text_nodisable_holo_light</item>
- <item name="textColorPrimaryInverseNoDisable">@color/primary_text_nodisable_holo_dark</item>
<item name="textColorSecondaryInverseNoDisable">@color/secondary_text_nodisable_holo_dark</item>
+ <item name="textColorTertiary">@color/tertiary_text_holo_light</item>
+ <item name="textColorTertiaryInverse">@color/tertiary_text_holo_dark</item>
<item name="textColorHint">@color/hint_foreground_holo_light</item>
<item name="textColorHintInverse">@color/hint_foreground_holo_dark</item>
- <item name="textColorSearchUrl">@color/search_url_text_holo</item>
<item name="textColorHighlight">@color/highlighted_text_holo_light</item>
<item name="textColorHighlightInverse">@color/highlighted_text_holo_dark</item>
<item name="textColorLink">@color/holo_blue_light</item>
<item name="textColorLinkInverse">@color/holo_blue_light</item>
+ <item name="textColorSearchUrl">@color/search_url_text_holo</item>
<item name="textColorAlertDialogListItem">@color/primary_text_holo_light</item>
<item name="textAppearanceLarge">@style/TextAppearance.Holo.Light.Large</item>
@@ -466,9 +488,6 @@ please see themes_device_defaults.xml.
<item name="editTextColor">?attr/textColorPrimary</item>
<item name="editTextBackground">@drawable/edit_text_holo_light</item>
- <item name="textEditSuggestionItemLayout">@layout/text_edit_suggestion_item</item>
- <item name="textEditSuggestionContainerLayout">@layout/text_edit_suggestion_container</item>
- <item name="textEditSuggestionHighlightStyle">@style/TextAppearance.Holo.SuggestionHighlight</item>
<item name="candidatesTextStyleSpans">@string/candidates_style</item>
@@ -477,6 +496,7 @@ please see themes_device_defaults.xml.
<item name="textAppearanceLargePopupMenu">@style/TextAppearance.Holo.Light.Widget.PopupMenu.Large</item>
<item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Holo.Light.Widget.PopupMenu.Small</item>
+ <item name="textAppearancePopupMenuHeader">@null</item>
<!-- Button styles -->
<item name="buttonStyle">@style/Widget.Holo.Light.Button</item>
@@ -485,6 +505,8 @@ please see themes_device_defaults.xml.
<item name="buttonStyleInset">@style/Widget.Holo.Light.Button.Inset</item>
<item name="buttonStyleToggle">@style/Widget.Holo.Light.Button.Toggle</item>
+ <item name="buttonCornerRadius">0dp</item>
+
<item name="switchStyle">@style/Widget.Holo.Light.CompoundButton.Switch</item>
<item name="mediaRouteButtonStyle">@style/Widget.Holo.Light.MediaRouteButton</item>
@@ -498,6 +520,7 @@ please see themes_device_defaults.xml.
<item name="listPreferredItemHeightSmall">48dip</item>
<item name="listPreferredItemHeightLarge">80dip</item>
<item name="dropdownListPreferredItemHeight">?attr/listPreferredItemHeightSmall</item>
+ <item name="textAppearanceListItem">?attr/textAppearanceLarge</item>
<item name="textAppearanceListItemSmall">?attr/textAppearanceMedium</item>
<item name="textAppearanceListItemSecondary">?attr/textAppearanceSmall</item>
<item name="listPreferredItemPaddingLeft">8dip</item>
@@ -514,9 +537,10 @@ please see themes_device_defaults.xml.
<item name="listChoiceIndicatorMultiple">@drawable/btn_check_holo_light</item>
<item name="listChoiceBackgroundIndicator">@drawable/list_selector_holo_light</item>
-
<item name="activatedBackgroundIndicator">@drawable/activated_background_holo_light</item>
+ <item name="listDividerAlertDialog">@drawable/list_divider_holo_light</item>
+
<item name="expandableListPreferredItemPaddingLeft">40dip</item>
<item name="expandableListPreferredChildPaddingLeft">?attr/expandableListPreferredItemPaddingLeft</item>
@@ -524,8 +548,6 @@ please see themes_device_defaults.xml.
<item name="expandableListPreferredItemIndicatorRight">0dip</item>
<item name="expandableListPreferredChildIndicatorLeft">?attr/expandableListPreferredItemIndicatorLeft</item>
<item name="expandableListPreferredChildIndicatorRight">?attr/expandableListPreferredItemIndicatorRight</item>
-
- <item name="listDividerAlertDialog">@drawable/list_divider_holo_light</item>
<item name="findOnPageNextDrawable">@drawable/ic_find_next_holo_light</item>
<item name="findOnPagePreviousDrawable">@drawable/ic_find_previous_holo_light</item>
@@ -553,6 +575,8 @@ please see themes_device_defaults.xml.
<item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_holo</item>
<item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_holo</item>
<item name="dialogTitleDecorLayout">@layout/dialog_title_holo</item>
+ <item name="dialogPreferredPadding">@dimen/dialog_padding</item>
+ <item name="dialogCornerRadius">0dp</item>
<!-- AlertDialog attributes -->
<item name="alertDialogTheme">@style/Theme.Holo.Light.Dialog.Alert</item>
@@ -592,6 +616,9 @@ please see themes_device_defaults.xml.
<item name="textSelectHandleRight">@drawable/text_select_handle_right_material</item>
<item name="textSelectHandle">@drawable/text_select_handle_middle_material</item>
<item name="textSelectHandleWindowStyle">@style/Widget.Holo.TextSelectHandle</item>
+ <item name="textEditSuggestionItemLayout">@layout/text_edit_suggestion_item</item>
+ <item name="textEditSuggestionContainerLayout">@layout/text_edit_suggestion_container</item>
+ <item name="textEditSuggestionHighlightStyle">@style/TextAppearance.Holo.SuggestionHighlight</item>
<item name="textCursorDrawable">@drawable/text_cursor_holo_light</item>
<!-- Widget styles -->
@@ -609,6 +636,7 @@ please see themes_device_defaults.xml.
<item name="gridViewStyle">@style/Widget.Holo.Light.GridView</item>
<item name="imageButtonStyle">@style/Widget.Holo.Light.ImageButton</item>
<item name="imageWellStyle">@style/Widget.Holo.Light.ImageWell</item>
+ <item name="listMenuViewStyle">@null</item>
<item name="listViewStyle">@style/Widget.Holo.Light.ListView</item>
<item name="listViewWhiteStyle">@style/Widget.Holo.Light.ListView.White</item>
<item name="popupWindowStyle">@style/Widget.Holo.Light.PopupWindow</item>
@@ -649,9 +677,11 @@ please see themes_device_defaults.xml.
<item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.Holo.QuickContactBadgeSmall.WindowLarge</item>
<item name="listPopupWindowStyle">@style/Widget.Holo.Light.ListPopupWindow</item>
<item name="popupMenuStyle">@style/Widget.Holo.Light.PopupMenu</item>
+ <item name="popupTheme">@null</item>
<item name="stackViewStyle">@style/Widget.Holo.StackView</item>
<item name="activityChooserViewStyle">@style/Widget.Holo.Light.ActivityChooserView</item>
<item name="fragmentBreadCrumbsStyle">@style/Widget.Holo.Light.FragmentBreadCrumbs</item>
+ <item name="contextPopupMenuStyle">@null</item>
<!-- Preference styles -->
<item name="preferenceScreenStyle">@style/Preference.Holo.PreferenceScreen</item>
@@ -668,6 +698,11 @@ please see themes_device_defaults.xml.
<item name="editTextPreferenceStyle">@style/Preference.Holo.DialogPreference.EditTextPreference</item>
<item name="ringtonePreferenceStyle">@style/Preference.Holo.RingtonePreference</item>
<item name="preferenceLayoutChild">@layout/preference_child_holo</item>
+ <item name="preferencePanelStyle">@null</item>
+ <item name="preferenceHeaderPanelStyle">@null</item>
+ <item name="preferenceListStyle">@null</item>
+ <item name="preferenceFragmentListStyle">@null</item>
+ <item name="preferenceFragmentPaddingSide">@null</item>
<item name="detailsElementBackground">@drawable/panel_bg_holo_light</item>
<!-- PreferenceFrameLayout attributes -->
@@ -680,6 +715,7 @@ please see themes_device_defaults.xml.
<item name="actionDropDownStyle">@style/Widget.Holo.Light.Spinner.DropDown.ActionBar</item>
<item name="actionButtonStyle">@style/Widget.Holo.Light.ActionButton</item>
<item name="actionOverflowButtonStyle">@style/Widget.Holo.Light.ActionButton.Overflow</item>
+ <item name="actionOverflowMenuStyle">?attr/popupMenuStyle</item>
<item name="actionModeBackground">@drawable/cab_background_top_holo_light</item>
<item name="actionModeSplitBackground">@drawable/cab_background_bottom_holo_light</item>
<item name="actionModeCloseDrawable">@drawable/ic_cab_done_holo_light</item>
@@ -691,8 +727,12 @@ please see themes_device_defaults.xml.
<item name="actionBarStyle">@style/Widget.Holo.Light.ActionBar.Solid</item>
<item name="actionBarSize">@dimen/action_bar_default_height</item>
<item name="actionModePopupWindowStyle">@style/Widget.Holo.Light.PopupWindow.ActionMode</item>
+ <item name="actionMenuTextAppearance">@null</item>
+ <item name="actionMenuTextColor">@null</item>
<item name="actionBarWidgetTheme">@null</item>
+ <item name="actionBarPopupTheme">?attr/popupTheme</item>
<item name="actionBarTheme">@null</item>
+ <item name="actionBarItemBackground">@null</item>
<item name="actionModeCutDrawable">@drawable/ic_menu_cut_holo_light</item>
<item name="actionModeCopyDrawable">@drawable/ic_menu_copy_holo_light</item>
@@ -702,6 +742,8 @@ please see themes_device_defaults.xml.
<item name="actionModeFindDrawable">@drawable/ic_menu_find_holo_light</item>
<item name="actionModeWebSearchDrawable">@drawable/ic_menu_search_holo_light</item>
+ <item name="toolbarStyle">@null</item>
+
<item name="dividerVertical">?attr/listDivider</item>
<item name="dividerHorizontal">?attr/listDivider</item>
<item name="buttonBarStyle">@style/Holo.Light.ButtonBar</item>
@@ -736,11 +778,37 @@ please see themes_device_defaults.xml.
<item name="fastScrollTrackDrawable">@drawable/fastscroll_track_holo_light</item>
<item name="fastScrollOverlayPosition">atThumb</item>
+ <!-- Color palette -->
+ <item name="colorPrimaryDark">@color/holo_light_primary_dark</item>
+ <item name="colorPrimary">@color/holo_light_primary</item>
+ <item name="colorAccent">@color/holo_blue_light</item>
+ <item name="colorEdgeEffect">?attr/colorPrimary</item>
+
+ <item name="colorControlNormal">@color/holo_light_control_normal</item>
+ <item name="colorControlActivated">@color/holo_light_control_activated</item>
+
+ <item name="colorControlHighlight">@color/holo_light_button_pressed</item>
+ <item name="colorButtonNormal">@color/holo_light_button_normal</item>
+ <item name="colorSwitchThumbNormal">@color/switch_thumb_material_light</item>
+
+ <!-- Tooltip popup properties -->
+ <item name="tooltipForegroundColor">@null</item>
+ <item name="tooltipBackgroundColor">@null</item>
+
+ <!-- Holo-only color attributes -->
+ <item name="colorPressedHighlight">@color/holo_gray_light</item>
+ <item name="colorLongPressedHighlight">@color/holo_gray_bright</item>
+ <item name="colorFocusedHighlight">@color/holo_blue_dark</item>
+ <item name="colorMultiSelectHighlight">@color/holo_green_light</item>
+ <item name="colorActivatedHighlight">@color/holo_blue_dark</item>
+
</style>
<!-- Variant of the holographic (light) theme that has a solid (opaque) action bar
with an inverse color profile. The dark action bar sharply stands out against
- the light content. -->
+ the light content.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Light.DarkActionBar">
<item name="windowContentOverlay">@drawable/ab_solid_shadow_holo</item>
<item name="actionBarStyle">@style/Widget.Holo.Light.ActionBar.Solid.Inverse</item>
@@ -773,7 +841,9 @@ please see themes_device_defaults.xml.
<item name="actionModeWebSearchDrawable">@drawable/ic_menu_search_holo_dark</item>
</style>
- <!-- Variant of the holographic (dark) theme with no action bar. -->
+ <!-- Variant of the holographic (dark) theme with no action bar.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
@@ -781,7 +851,9 @@ please see themes_device_defaults.xml.
<!-- Variant of the holographic (dark) theme that has no title bar and fills
the entire screen. This theme
- sets {@link android.R.attr#windowFullscreen} to true. -->
+ sets {@link android.R.attr#windowFullscreen} to true.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.NoActionBar.Fullscreen">
<item name="windowFullscreen">true</item>
<item name="windowContentOverlay">@null</item>
@@ -790,7 +862,9 @@ please see themes_device_defaults.xml.
<!-- Variant of the holographic (dark) theme that has no title bar and fills
the entire screen and extends into the display overscan region. This theme
sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
- to true. -->
+ to true.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.NoActionBar.Overscan">
<item name="windowFullscreen">true</item>
<item name="windowOverscan">true</item>
@@ -799,14 +873,18 @@ please see themes_device_defaults.xml.
<!-- Variant of the holographic (dark) theme that has no title bar and translucent
system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
- {@link android.R.attr#windowTranslucentNavigation} to true. -->
+ {@link android.R.attr#windowTranslucentNavigation} to true.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.NoActionBar.TranslucentDecor">
<item name="windowTranslucentStatus">true</item>
<item name="windowTranslucentNavigation">true</item>
<item name="windowContentOverlay">@null</item>
</style>
- <!-- Variant of the holographic (light) theme with no action bar. -->
+ <!-- Variant of the holographic (light) theme with no action bar.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Light.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
@@ -814,7 +892,9 @@ please see themes_device_defaults.xml.
<!-- Variant of the holographic (light) theme that has no title bar and fills
the entire screen. This theme
- sets {@link android.R.attr#windowFullscreen} to true. -->
+ sets {@link android.R.attr#windowFullscreen} to true.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Light.NoActionBar.Fullscreen">
<item name="windowFullscreen">true</item>
<item name="windowContentOverlay">@null</item>
@@ -823,7 +903,9 @@ please see themes_device_defaults.xml.
<!-- Variant of the holographic (light) theme that has no title bar and fills
the entire screen and extends into the display overscan region. This theme
sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
- to true. -->
+ to true.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Light.NoActionBar.Overscan">
<item name="windowFullscreen">true</item>
<item name="windowOverscan">true</item>
@@ -832,7 +914,9 @@ please see themes_device_defaults.xml.
<!-- Variant of the holographic (light) theme that has no title bar and translucent
system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
- {@link android.R.attr#windowTranslucentNavigation} to true. -->
+ {@link android.R.attr#windowTranslucentNavigation} to true.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Light.NoActionBar.TranslucentDecor">
<item name="windowTranslucentStatus">true</item>
<item name="windowTranslucentNavigation">true</item>
@@ -848,7 +932,9 @@ please see themes_device_defaults.xml.
contents. You can set this theme on an activity if you would like to
make an activity that looks like a Dialog.
This is the default Dialog theme for applications targeting Honeycomb
- or newer. -->
+ or newer.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Dialog">
<item name="windowFrame">@null</item>
<item name="windowTitleStyle">@style/DialogWindowTitle.Holo</item>
@@ -878,26 +964,34 @@ please see themes_device_defaults.xml.
</style>
<!-- Variant of Theme.Holo.Dialog that has a nice minimum width for
- a regular dialog. -->
+ a regular dialog.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Dialog.MinWidth">
<item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
<item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
</style>
- <!-- Variant of Theme.Holo.Dialog that does not include a title bar. -->
+ <!-- Variant of Theme.Holo.Dialog that does not include a title bar.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Dialog.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<!-- Variant of Theme.Holo.Dialog.NoActionBar that has a nice minimum width for
- a regular dialog. -->
+ a regular dialog.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Dialog.NoActionBar.MinWidth">
<item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
<item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
</style>
- <!-- Variant of Theme.Holo.Dialog that has a fixed size. -->
+ <!-- Variant of Theme.Holo.Dialog that has a fixed size.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Dialog.FixedSize">
<item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
<item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
@@ -905,7 +999,9 @@ please see themes_device_defaults.xml.
<item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
</style>
- <!-- Variant of Theme.Holo.Dialog.NoActionBar that has a fixed size. -->
+ <!-- Variant of Theme.Holo.Dialog.NoActionBar that has a fixed size.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Dialog.NoActionBar.FixedSize">
<item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
<item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
@@ -915,7 +1011,9 @@ please see themes_device_defaults.xml.
<!-- Variant of Theme.Holo.Dialog that does not include a frame (or background).
The view hierarchy of the dialog is responsible for drawing all of
- its pixels. -->
+ its pixels.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Dialog.NoFrame">
<item name="windowBackground">@color/transparent</item>
<item name="windowFrame">@null</item>
@@ -939,20 +1037,28 @@ please see themes_device_defaults.xml.
{@link android.app.AlertDialog} class. This is basically a dialog
but sets the background to empty so it can do two-tone backgrounds.
For applications targeting Honeycomb or newer, this is the default
- AlertDialog theme. -->
+ AlertDialog theme.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Dialog.Alert" parent="Theme.Holo.Dialog.BaseAlert" />
<!-- Theme for a window that will be displayed either full-screen on
smaller screens (small, normal) or as a dialog on larger screens
- (large, xlarge). -->
+ (large, xlarge).
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.DialogWhenLarge" parent="Theme.Holo" />
<!-- Theme for a window without a title bar that will be displayed either
full-screen on smaller screens (small, normal) or as a dialog on larger screens
- (large, xlarge). -->
+ (large, xlarge).
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.DialogWhenLarge.NoActionBar" parent="Theme.Holo.NoActionBar" />
- <!-- Theme for a presentation window on a secondary display. -->
+ <!-- Theme for a presentation window on a secondary display.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Dialog.Presentation" parent="Theme.Holo.NoActionBar.Fullscreen" />
<!-- Light holo dialog themes -->
@@ -963,7 +1069,9 @@ please see themes_device_defaults.xml.
contents. You can set this theme on an activity if you would like to
make an activity that looks like a Dialog.
This is the default Dialog theme for applications targeting Honeycomb
- or newer. -->
+ or newer.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Light.Dialog">
<item name="windowFrame">@null</item>
<item name="windowTitleStyle">@style/DialogWindowTitle.Holo.Light</item>
@@ -993,26 +1101,34 @@ please see themes_device_defaults.xml.
</style>
<!-- Variant of Theme.Holo.Light.Dialog that has a nice minimum width for
- a regular dialog. -->
+ a regular dialog.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Light.Dialog.MinWidth">
<item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
<item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
</style>
- <!-- Variant of Theme.Holo.Light.Dialog that does not include a title bar. -->
+ <!-- Variant of Theme.Holo.Light.Dialog that does not include a title bar.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Light.Dialog.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<!-- Variant of Theme.Holo.Light.Dialog.NoActionBar that has a nice minimum width for
- a regular dialog. -->
+ a regular dialog.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Light.Dialog.NoActionBar.MinWidth">
<item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
<item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
</style>
- <!-- Variant of Theme.Holo.Light.Dialog that has a fixed size. -->
+ <!-- Variant of Theme.Holo.Light.Dialog that has a fixed size.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Light.Dialog.FixedSize">
<item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
<item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
@@ -1020,7 +1136,9 @@ please see themes_device_defaults.xml.
<item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
</style>
- <!-- Variant of Theme.Holo.Light.Dialog.NoActionBar that has a fixed size. -->
+ <!-- Variant of Theme.Holo.Light.Dialog.NoActionBar that has a fixed size.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Light.Dialog.NoActionBar.FixedSize">
<item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
<item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
@@ -1030,12 +1148,16 @@ please see themes_device_defaults.xml.
<!-- Theme for a window that will be displayed either full-screen on
smaller screens (small, normal) or as a dialog on larger screens
- (large, xlarge). -->
+ (large, xlarge).
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Light.DialogWhenLarge" parent="Theme.Holo.Light" />
<!-- Theme for a window without an action bar that will be displayed either full-screen
on smaller screens (small, normal) or as a dialog on larger screens
- (large, xlarge). -->
+ (large, xlarge).
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Light.DialogWhenLarge.NoActionBar" parent="Theme.Holo.Light.NoActionBar" />
<style name="Theme.Holo.Light.Dialog.BaseAlert">
@@ -1050,14 +1172,20 @@ please see themes_device_defaults.xml.
{@link android.app.AlertDialog} class. This is basically a dialog
but sets the background to empty so it can do two-tone backgrounds.
For applications targeting Honeycomb or newer, this is the default
- AlertDialog theme. -->
+ AlertDialog theme.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Holo.Light.Dialog.BaseAlert" />
- <!-- Theme for a presentation window on a secondary display. -->
+ <!-- Theme for a presentation window on a secondary display.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Light.Dialog.Presentation" parent="Theme.Holo.Light.NoActionBar.Fullscreen" />
<!-- Default holographic (dark) for windows that want to have the user's selected
- wallpaper appear behind them. -->
+ wallpaper appear behind them.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Wallpaper">
<item name="windowBackground">@color/transparent</item>
<item name="colorBackgroundCacheHint">@null</item>
@@ -1065,7 +1193,9 @@ please see themes_device_defaults.xml.
</style>
<!--Default holographic (dark) for windows that want to have the user's selected
- wallpaper appear behind them and without an action bar. -->
+ wallpaper appear behind them and without an action bar.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Wallpaper.NoTitleBar">
<item name="windowNoTitle">true</item>
</style>
@@ -1073,7 +1203,9 @@ please see themes_device_defaults.xml.
<!-- Default holo dark theme for panel windows. This removes all extraneous
window decorations, so you basically have an empty rectangle in which
to place your content. It makes the window floating, with a transparent
- background, and turns off dimming behind the window. -->
+ background, and turns off dimming behind the window.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Panel">
<item name="windowBackground">@color/transparent</item>
<item name="colorBackgroundCacheHint">@null</item>
@@ -1089,7 +1221,9 @@ please see themes_device_defaults.xml.
<!-- Default holo light theme for panel windows. This removes all extraneous
window decorations, so you basically have an empty rectangle in which
to place your content. It makes the window floating, with a transparent
- background, and turns off dimming behind the window. -->
+ background, and turns off dimming behind the window.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Light.Panel">
<item name="windowBackground">@color/transparent</item>
<item name="colorBackgroundCacheHint">@null</item>
@@ -1105,7 +1239,9 @@ please see themes_device_defaults.xml.
<!-- Default theme for holo style input methods, which is used by the
{@link android.inputmethodservice.InputMethodService} class.
this inherits from Theme.Panel, but sets up IME appropriate animations
- and a few custom attributes. -->
+ and a few custom attributes.
+
+ @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.InputMethod" parent="Theme.Holo.Light.Panel">
<item name="windowAnimationStyle">@style/Animation.InputMethod</item>
<item name="imeFullscreenBackground">@drawable/screen_background_selector_light</item>
@@ -1113,17 +1249,19 @@ please see themes_device_defaults.xml.
<item name="imeExtractExitAnimation">@anim/input_method_extract_exit</item>
</style>
-
+ <!-- @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.SearchBar" parent="Theme.Holo.Panel">
<item name="actionModeBackground">@drawable/cab_background_top_holo_dark</item>
<item name="actionModeSplitBackground">@drawable/cab_background_bottom_holo_light</item>
</style>
+ <!-- @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Light.SearchBar" parent="Theme.Holo.Light.Panel">
<item name="actionModeBackground">@drawable/cab_background_top_holo_light</item>
<item name="actionModeSplitBackground">@drawable/cab_background_bottom_holo_light</item>
</style>
+ <!-- @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.CompactMenu">
<!-- Menu/item attributes -->
<item name="itemTextAppearance">?attr/textAppearanceMedium</item>
@@ -1132,6 +1270,7 @@ please see themes_device_defaults.xml.
<item name="background">@null</item>
</style>
+ <!-- @deprecated Use Material themes on API 21+ or AppCompat on supported APIs. -->
<style name="Theme.Holo.Light.CompactMenu">
<!-- Menu/item attributes -->
<item name="itemTextAppearance">?attr/textAppearanceMedium</item>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 15d8fb7b184d..6ae0ef3da225 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -384,7 +384,6 @@ please see themes_device_defaults.xml.
<!-- DatePicker dialog theme -->
<item name="datePickerDialogTheme">@style/ThemeOverlay.Material.Dialog.DatePicker</item>
- <!-- TODO: This belongs in a FastScroll style -->
<item name="fastScrollThumbDrawable">@drawable/fastscroll_thumb_material</item>
<item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_material</item>
<item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_material</item>
diff --git a/core/res/res/xml/default_zen_mode_config.xml b/core/res/res/xml/default_zen_mode_config.xml
index a446088fb93d..7849a2ace638 100644
--- a/core/res/res/xml/default_zen_mode_config.xml
+++ b/core/res/res/xml/default_zen_mode_config.xml
@@ -18,7 +18,7 @@
-->
<!-- Default configuration for zen mode. See android.service.notification.ZenModeConfig. -->
-<zen version="2">
+<zen version="3">
<allow alarms="true" media_system_other="true" calls="false" messages="false" reminders="false"
events="false" />
</zen>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 5bb9abefb535..67c975496fbf 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -354,6 +354,7 @@ public class SettingsBackupTest {
Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS,
Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG,
Settings.Global.SHOW_TEMPERATURE_WARNING,
+ Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION,
Settings.Global.SMART_SELECTION_UPDATE_CONTENT_URL,
Settings.Global.SMART_SELECTION_UPDATE_METADATA_URL,
Settings.Global.SMS_OUTGOING_CHECK_INTERVAL_MS,
@@ -366,6 +367,7 @@ public class SettingsBackupTest {
Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS,
Settings.Global.STORAGE_BENCHMARK_INTERVAL,
Settings.Global.STORAGE_SETTINGS_CLOBBER_THRESHOLD,
+ Settings.Global.SYNC_MANAGER_CONSTANTS,
Settings.Global.SYNC_MAX_RETRY_DELAY_IN_SECONDS,
Settings.Global.SYS_FREE_STORAGE_LOG_INTERVAL,
Settings.Global.SYS_STORAGE_CACHE_MAX_BYTES,
@@ -400,6 +402,8 @@ public class SettingsBackupTest {
Settings.Global.GPU_DEBUG_APP,
Settings.Global.GPU_DEBUG_LAYERS,
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
+ Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT,
+ Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS,
Settings.Global.NETWORK_ACCESS_TIMEOUT_MS,
Settings.Global.WARNING_TEMPERATURE,
Settings.Global.WEBVIEW_DATA_REDUCTION_PROXY_KEY,
@@ -450,7 +454,8 @@ public class SettingsBackupTest {
Settings.Global.ZEN_MODE_RINGER_LEVEL,
Settings.Global.ZRAM_ENABLED,
Settings.Global.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION,
- Settings.Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED);
+ Settings.Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED,
+ Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS);
private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS =
newHashSet(
@@ -465,6 +470,7 @@ public class SettingsBackupTest {
Settings.Secure.ASSIST_SCREENSHOT_ENABLED,
Settings.Secure.ASSIST_STRUCTURE_ENABLED,
Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION,
+ Settings.Secure.AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT,
Settings.Secure.AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE,
Settings.Secure.AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE,
Settings.Secure.AUTOFILL_USER_DATA_MAX_VALUE_LENGTH,
@@ -492,6 +498,7 @@ public class SettingsBackupTest {
Settings.Secure.DOZE_ALWAYS_ON,
Settings.Secure.DOZE_PULSE_ON_LONG_PRESS,
Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION,
+ Settings.Secure.ENABLED_INPUT_METHODS, // Intentionally removed in P
Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT,
Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
diff --git a/core/tests/coretests/src/android/text/OWNERS b/core/tests/coretests/src/android/text/OWNERS
index 9f2182eca908..a35c6042bf53 100644
--- a/core/tests/coretests/src/android/text/OWNERS
+++ b/core/tests/coretests/src/android/text/OWNERS
@@ -1,3 +1,5 @@
+set noparent
+
siyamed@google.com
nona@google.com
-clarabayarri@google.com
+clarabayarri@google.com \ No newline at end of file
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index a8de374cf30b..430b30fcbffe 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -19,6 +19,7 @@ package android.view.textclassifier;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import android.os.LocaleList;
@@ -33,6 +34,8 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TextClassificationManagerTest {
@@ -183,6 +186,7 @@ public class TextClassificationManagerTest {
@Test
public void testGenerateLinks_none_config() {
if (isTextClassifierDisabled()) return;
+
String text = "The number is +12122537077. See you tonight!";
assertThat(mClassifier.generateLinks(text, mLinksOptions.setEntityConfig(
new TextClassifier.EntityConfig(TextClassifier.ENTITY_PRESET_NONE))),
@@ -210,6 +214,25 @@ public class TextClassificationManagerTest {
}
@Test
+ public void testGenerateLinks_maxLength() {
+ if (isTextClassifierDisabled()) return;
+ char[] manySpaces = new char[mClassifier.getMaxGenerateLinksTextLength()];
+ Arrays.fill(manySpaces, ' ');
+ TextLinks links = mClassifier.generateLinks(new String(manySpaces), null);
+ assertTrue(links.getLinks().isEmpty());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testGenerateLinks_tooLong() {
+ if (isTextClassifierDisabled()) {
+ throw new IllegalArgumentException("pass if disabled");
+ }
+ char[] manySpaces = new char[mClassifier.getMaxGenerateLinksTextLength() + 1];
+ Arrays.fill(manySpaces, ' ');
+ mClassifier.generateLinks(new String(manySpaces), null);
+ }
+
+ @Test
public void testSetTextClassifier() {
TextClassifier classifier = mock(TextClassifier.class);
mTcm.setTextClassifier(classifier);
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 7f4f9f7b928a..79433ac67aa0 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -382,7 +382,7 @@ public class TextViewActivityTest {
TextClassifier textClassifier = textClassificationManager.getTextClassifier();
Spannable content = new SpannableString("Call me at +19148277737");
TextLinks links = textClassifier.generateLinks(content);
- links.apply(content, TextLinks.APPLY_STRATEGY_REPLACE, null);
+ links.apply(content, TextLinks.APPLY_STRATEGY_REPLACE, null, false /* allowPrefix */);
mActivityRule.runOnUiThread(() -> {
textView.setText(content);
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
index 32053e30e886..cb049b780fa8 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
@@ -114,7 +114,7 @@ public class BatteryStatsCpuTimesTest {
when(mKernelUidCpuFreqTimeReader.readFreqs(mPowerProfile)).thenReturn(freqs);
// RUN
- mBatteryStatsImpl.updateCpuTimeLocked();
+ mBatteryStatsImpl.updateCpuTimeLocked(false, false);
// VERIFY
assertArrayEquals("Unexpected cpu freqs", freqs, mBatteryStatsImpl.getCpuFreqs());
@@ -134,7 +134,7 @@ public class BatteryStatsCpuTimesTest {
mBatteryStatsImpl.setOnBatteryInternal(true);
// RUN
- mBatteryStatsImpl.updateCpuTimeLocked();
+ mBatteryStatsImpl.updateCpuTimeLocked(true, false);
// VERIFY
verify(mUserInfoProvider).refreshUserIds();
@@ -213,7 +213,7 @@ public class BatteryStatsCpuTimesTest {
}
// RUN
- mBatteryStatsImpl.updateClusterSpeedTimes(updatedUids);
+ mBatteryStatsImpl.updateClusterSpeedTimes(updatedUids, true);
// VERIFY
int totalClustersTimeMs = 0;
@@ -261,7 +261,7 @@ public class BatteryStatsCpuTimesTest {
// RUN
final SparseLongArray updatedUids = new SparseLongArray();
- mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, updatedUids);
+ mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, updatedUids, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -294,7 +294,7 @@ public class BatteryStatsCpuTimesTest {
}).when(mKernelUidCpuTimeReader).readDelta(any(KernelUidCpuTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null);
+ mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -333,7 +333,7 @@ public class BatteryStatsCpuTimesTest {
}).when(mKernelUidCpuTimeReader).readDelta(any(KernelUidCpuTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null);
+ mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -368,7 +368,7 @@ public class BatteryStatsCpuTimesTest {
}).when(mKernelUidCpuTimeReader).readDelta(any(KernelUidCpuTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null);
+ mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -423,7 +423,7 @@ public class BatteryStatsCpuTimesTest {
}).when(mKernelUidCpuTimeReader).readDelta(any(KernelUidCpuTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null);
+ mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -470,7 +470,7 @@ public class BatteryStatsCpuTimesTest {
// RUN
final SparseLongArray updatedUids = new SparseLongArray();
- mBatteryStatsImpl.readKernelUidCpuTimesLocked(partialTimers, updatedUids);
+ mBatteryStatsImpl.readKernelUidCpuTimesLocked(partialTimers, updatedUids, true);
// VERIFY
long totalUserTimeUs = 0;
@@ -549,7 +549,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -582,7 +582,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -633,7 +633,7 @@ public class BatteryStatsCpuTimesTest {
when(mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()).thenReturn(true);
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -676,7 +676,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -743,7 +743,7 @@ public class BatteryStatsCpuTimesTest {
when(mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()).thenReturn(true);
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(partialTimers);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(partialTimers, true, false);
// VERIFY
final long[][] expectedWakeLockUidTimesUs = new long[clusterFreqs.length][];
@@ -832,7 +832,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -865,7 +865,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -909,7 +909,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -949,7 +949,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -1006,7 +1006,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -1047,7 +1047,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelUidCpuActiveTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked();
+ mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked(true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -1073,7 +1073,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelUidCpuActiveTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked();
+ mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked(true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -1112,7 +1112,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelUidCpuClusterTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked();
+ mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -1142,7 +1142,7 @@ public class BatteryStatsCpuTimesTest {
any(KernelUidCpuClusterTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked();
+ mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index 82ac9da575d7..01ddc15efb47 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -161,9 +161,7 @@ public class BatteryStatsNoteTest extends TestCase {
actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE,
elapsedTimeUs, STATS_SINCE_CHARGED);
- expectedRunTimeMs = stateRuntimeMap.get(
- ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE)
- + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+ expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING,
@@ -173,7 +171,8 @@ public class BatteryStatsNoteTest extends TestCase {
actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_FOREGROUND,
elapsedTimeUs, STATS_SINCE_CHARGED);
- expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+ expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)
+ + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_BACKGROUND,
diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
index d425dcc7f592..42c9139e04e2 100644
--- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
@@ -25,6 +25,7 @@ import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP;
import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING;
import static android.os.BatteryStats.Uid.UID_PROCESS_TYPES;
+import static com.android.internal.os.BatteryStatsImpl.Constants.KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS;
import static com.android.internal.os.BatteryStatsImpl.Constants.KEY_TRACK_CPU_TIMES_BY_PROC_STATE;
import static junit.framework.Assert.assertNotNull;
@@ -101,6 +102,11 @@ public class BstatsCpuTimesValidationTest {
private static final int WORK_DURATION_MS = 2000;
+ private static final String DESIRED_PROC_STATE_CPU_TIMES_DELAY = "0";
+
+ private static boolean sBatteryStatsConstsUpdated;
+ private static String sOriginalBatteryStatsConsts;
+
private static Context sContext;
private static UiDevice sUiDevice;
private static int sTestPkgUid;
@@ -117,13 +123,43 @@ public class BstatsCpuTimesValidationTest {
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
sTestPkgUid = sContext.getPackageManager().getPackageUid(TEST_PKG, 0);
checkCpuTimesAvailability();
+ if (sPerProcStateTimesAvailable && sCpuFreqTimesAvailable) {
+ setDesiredReadyDelay();
+ }
}
@AfterClass
public static void tearDownOnce() throws Exception {
+ if (sBatteryStatsConstsUpdated) {
+ Settings.Global.putString(sContext.getContentResolver(),
+ Settings.Global.BATTERY_STATS_CONSTANTS, sOriginalBatteryStatsConsts);
+ }
batteryReset();
}
+ private static void setDesiredReadyDelay() {
+ sOriginalBatteryStatsConsts = Settings.Global.getString(sContext.getContentResolver(),
+ Settings.Global.BATTERY_STATS_CONSTANTS);
+ String newBatteryStatsConstants;
+ final String newConstant = KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS
+ + "=" + DESIRED_PROC_STATE_CPU_TIMES_DELAY;
+ if (sOriginalBatteryStatsConsts == null || "null".equals(sOriginalBatteryStatsConsts)) {
+ // battery_stats_constants is initially empty, so just assign the desired value.
+ newBatteryStatsConstants = newConstant;
+ } else if (sOriginalBatteryStatsConsts.contains(KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS)) {
+ // battery_stats_constants contains delay duration, so replace it
+ // with the desired value.
+ newBatteryStatsConstants = sOriginalBatteryStatsConsts.replaceAll(
+ KEY_PROC_STATE_CPU_TIMES_READ_DELAY_MS + "=\\d+", newConstant);
+ } else {
+ // battery_stats_constants didn't contain any delay, so append the desired value.
+ newBatteryStatsConstants = sOriginalBatteryStatsConsts + "," + newConstant;
+ }
+ Settings.Global.putString(sContext.getContentResolver(),
+ Settings.Global.BATTERY_STATS_CONSTANTS, newBatteryStatsConstants);
+ sBatteryStatsConstsUpdated = true;
+ }
+
// Checks cpu freq times of system uid as an indication of whether /proc/uid_time_in_state
// and /proc/uid/<uid>/time_in_state kernel nodes are available.
private static void checkCpuTimesAvailability() throws Exception {
@@ -132,9 +168,9 @@ public class BstatsCpuTimesValidationTest {
batteryOff();
final long[] totalCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID);
sCpuFreqTimesAvailable = totalCpuTimes != null;
- final long[] fgSvcCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID,
+ final long[] fgCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID,
PROCESS_STATE_FOREGROUND);
- sPerProcStateTimesAvailable = fgSvcCpuTimes != null;
+ sPerProcStateTimesAvailable = fgCpuTimes != null;
}
@Test
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
index 5d72942b53fc..29227f9f6a1b 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
@@ -115,6 +115,30 @@ public class KernelSingleUidTimeReaderTest {
}
@Test
+ public void readDelta_incorrectCount() {
+ assertTrue(mReader.singleUidCpuTimesAvailable());
+
+ long[] cpuTimes = new long[TEST_FREQ_COUNT - 1];
+ for (int i = 0; i < cpuTimes.length; ++i) {
+ cpuTimes[i] = 111 + i;
+ }
+ mInjector.setData(cpuTimes);
+ assertCpuTimesEqual(null, mReader.readDeltaMs(TEST_UID));
+ assertFalse(mReader.singleUidCpuTimesAvailable());
+
+ // Reset
+ mReader.setSingleUidCpuTimesAvailable(true);
+
+ cpuTimes = new long[TEST_FREQ_COUNT + 1];
+ for (int i = 0; i < cpuTimes.length; ++i) {
+ cpuTimes[i] = 222 + i;
+ }
+ mInjector.setData(cpuTimes);
+ assertCpuTimesEqual(null, mReader.readDeltaMs(TEST_UID));
+ assertFalse(mReader.singleUidCpuTimesAvailable());
+ }
+
+ @Test
public void testComputeDelta() {
// proc file not available
mReader.setSingleUidCpuTimesAvailable(false);
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index 7b239f05c0d3..6d5c7e7749e8 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -160,8 +160,8 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
}
@Override
- public Future<?> scheduleReadProcStateCpuTimes(
- boolean onBattery, boolean onBatteryScreenOff) {
+ public Future<?> scheduleReadProcStateCpuTimes(boolean onBattery,
+ boolean onBatteryScreenOff, long delayMillis) {
return null;
}
@@ -171,6 +171,20 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
return null;
}
+ @Override
+ public Future<?> scheduleCpuSyncDueToScreenStateChange(
+ boolean onBattery, boolean onBatteryScreenOff) {
+ return null;
+ }
+
+ @Override
+ public Future<?> scheduleCpuSyncDueToWakelockChange(long delayMillis) {
+ return null;
+ }
+
+ @Override
+ public void cancelCpuSyncDueToWakelockChange() {
+ }
}
}
diff --git a/core/tests/featureflagtests/OWNERS b/core/tests/featureflagtests/OWNERS
new file mode 100644
index 000000000000..1a8fd2b62f9a
--- /dev/null
+++ b/core/tests/featureflagtests/OWNERS
@@ -0,0 +1,2 @@
+sbasi@google.com
+zhfan@google.com \ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk b/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk
index 994131a22ab3..9b9e8113f234 100644
--- a/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk
+++ b/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk
@@ -29,13 +29,10 @@ LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES:= \
native.cpp
-# All of the shard libraries we link against.
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_LDLIBS := -llog
LOCAL_CFLAGS += -Wall -Wextra -Werror
-# Also need the JNI headers.
-LOCAL_C_INCLUDES += \
- $(JNI_H_INCLUDE)
+LOCAL_SDK_VERSION := current
include $(BUILD_SHARED_LIBRARY)
diff --git a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
index 99cf587af2a6..fe32454aa10d 100644
--- a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
@@ -15,12 +15,15 @@
*/
#define LOG_TAG "pmtest32 native.cpp"
-#include <utils/Log.h>
+#include <android/log.h>
#include <stdio.h>
#include "jni.h"
+#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+
static jint
add(JNIEnv */* env */, jobject /* thiz */, jint a, jint b) {
int result = a + b;
diff --git a/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk b/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk
index 6c2679b30bfb..600a5d148740 100644
--- a/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk
+++ b/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk
@@ -30,14 +30,10 @@ LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES:= \
native.cpp
-# All of the shared libraries we link against.
-LOCAL_SHARED_LIBRARIES := \
- libutils liblog
+LOCAL_LDLIBS := -llog
LOCAL_CFLAGS += -Wall -Wextra -Werror
-# Also need the JNI headers.
-LOCAL_C_INCLUDES += \
- $(JNI_H_INCLUDE)
+LOCAL_SDK_VERSION := current
include $(BUILD_SHARED_LIBRARY)
diff --git a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
index 0b6d7501dcae..ad9e7469d1b8 100644
--- a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
@@ -15,12 +15,15 @@
*/
#define LOG_TAG "pmtest64 native.cpp"
-#include <utils/Log.h>
+#include <android/log.h>
#include <stdio.h>
#include "jni.h"
+#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+
static jint
add(JNIEnv */* env */, jobject /* thiz */, jint a, jint b) {
int result = a + b;
diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk b/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk
index d668f29456c8..8e9ac6b5de95 100644
--- a/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk
+++ b/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk
@@ -29,14 +29,10 @@ LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES:= \
native.cpp
-# All of the shard libraries we link against.
LOCAL_LDLIBS = -llog
-LOCAL_SHARED_LIBRARIES := liblog
LOCAL_CFLAGS += -Wall -Wextra -Werror
-# Also need the JNI headers.
-LOCAL_C_INCLUDES += \
- $(JNI_H_INCLUDE)
+LOCAL_SDK_VERSION := current
include $(BUILD_SHARED_LIBRARY)
diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
index 3947e21a77bd..5c5088f40a94 100644
--- a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
@@ -15,12 +15,15 @@
*/
#define LOG_TAG "pmtestdual native.cpp"
-#include <utils/Log.h>
+#include <android/log.h>
#include <stdio.h>
#include "jni.h"
+#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+
static jint
add(JNIEnv */* env */, jobject /* thiz */, jint a, jint b) {
int result = a + b;
diff --git a/docs/html/reference/images/text/style/typefacespan.png b/docs/html/reference/images/text/style/typefacespan.png
index 67e2cf9b0468..1651c390e715 100644
--- a/docs/html/reference/images/text/style/typefacespan.png
+++ b/docs/html/reference/images/text/style/typefacespan.png
Binary files differ
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index acefead785c4..3cca47b47a59 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -25,7 +25,7 @@ import android.annotation.Nullable;
import android.annotation.RawRes;
import android.content.ContentResolver;
import android.content.res.AssetFileDescriptor;
-import android.content.res.AssetManager;
+import android.content.res.AssetManager.AssetInputStream;
import android.content.res.Resources;
import android.graphics.drawable.AnimatedImageDrawable;
import android.graphics.drawable.Drawable;
@@ -263,6 +263,63 @@ public final class ImageDecoder implements AutoCloseable {
}
}
+ /**
+ * Takes ownership of the AssetInputStream.
+ *
+ * @hide
+ */
+ public static class AssetInputStreamSource extends Source {
+ public AssetInputStreamSource(@NonNull AssetInputStream ais,
+ @NonNull Resources res, @NonNull TypedValue value) {
+ mAssetInputStream = ais;
+ mResources = res;
+
+ if (value.density == TypedValue.DENSITY_DEFAULT) {
+ mDensity = DisplayMetrics.DENSITY_DEFAULT;
+ } else if (value.density != TypedValue.DENSITY_NONE) {
+ mDensity = value.density;
+ } else {
+ mDensity = Bitmap.DENSITY_NONE;
+ }
+ }
+
+ private AssetInputStream mAssetInputStream;
+ private final Resources mResources;
+ private final int mDensity;
+
+ @Override
+ public Resources getResources() { return mResources; }
+
+ @Override
+ public int getDensity() {
+ return mDensity;
+ }
+
+ @Override
+ public ImageDecoder createImageDecoder() throws IOException {
+ ImageDecoder decoder = null;
+ synchronized (this) {
+ if (mAssetInputStream == null) {
+ throw new IOException("Cannot reuse AssetInputStreamSource");
+ }
+ AssetInputStream ais = mAssetInputStream;
+ mAssetInputStream = null;
+ try {
+ long asset = ais.getNativeAsset();
+ decoder = nCreate(asset);
+ } finally {
+ if (decoder == null) {
+ IoUtils.closeQuietly(ais);
+ } else {
+ decoder.mInputStream = ais;
+ decoder.mOwnsInputStream = true;
+ }
+ }
+ return decoder;
+ }
+ }
+ }
+
private static class ResourceSource extends Source {
ResourceSource(@NonNull Resources res, int resId) {
mResources = res;
@@ -296,11 +353,7 @@ public final class ImageDecoder implements AutoCloseable {
mResDensity = value.density;
}
- if (!(is instanceof AssetManager.AssetInputStream)) {
- // This should never happen.
- throw new RuntimeException("Resource is not an asset?");
- }
- long asset = ((AssetManager.AssetInputStream) is).getNativeAsset();
+ long asset = ((AssetInputStream) is).getNativeAsset();
decoder = nCreate(asset);
} finally {
if (decoder == null) {
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index a56e8d1b25ed..66f2a3173eae 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -667,8 +667,9 @@ public class NinePatchDrawable extends Drawable {
return;
}
- final int sourceDensity = ninePatch.getDensity();
final int targetDensity = mTargetDensity;
+ final int sourceDensity = ninePatch.getDensity() == Bitmap.DENSITY_NONE ?
+ targetDensity : ninePatch.getDensity();
final Insets sourceOpticalInsets = mNinePatchState.mOpticalInsets;
if (sourceOpticalInsets != Insets.NONE) {
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index 41d36986dfe2..2812abe067f7 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -78,9 +78,10 @@ class RippleBackground extends RippleComponent {
}
private void onStateChanged() {
- float newOpacity = 0.0f;
- if (mHovered) newOpacity += .25f;
- if (mFocused) newOpacity += .75f;
+ // Hover = .2 * alpha
+ // Focus = .6 * alpha
+ // Focused + Hovered = .6 * alpha
+ float newOpacity = mFocused ? .6f : mHovered ? .2f : 0f;
if (mAnimator != null) {
mAnimator.cancel();
mAnimator = null;
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index ded427eb244a..e2aba0401036 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -545,7 +545,9 @@ public class KeyStore {
try {
args = args != null ? args : new KeymasterArguments();
entropy = entropy != null ? entropy : new byte[0];
- return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid);
+ OperationResult res = mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid);
+ // This result is -26 (KEY_USER_NOT_AUTHENTICATED) but why??
+ return res;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return null;
@@ -563,7 +565,8 @@ public class KeyStore {
try {
arguments = arguments != null ? arguments : new KeymasterArguments();
input = input != null ? input : new byte[0];
- return mBinder.update(token, arguments, input);
+ OperationResult res = mBinder.update(token, arguments, input);
+ return res;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return null;
@@ -618,9 +621,9 @@ public class KeyStore {
* @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to
* a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
*/
- public int addAuthToken(byte[] authToken) {
+ public int addAuthToken(byte[] authToken, int userId) {
try {
- return mBinder.addAuthToken(authToken);
+ return mBinder.addAuthToken(authToken, userId);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
@@ -832,14 +835,14 @@ public class KeyStore {
public InvalidKeyException getInvalidKeyException(
String keystoreKeyAlias, int uid, KeyStoreException e) {
switch (e.getErrorCode()) {
- case LOCKED:
+ case LOCKED: // 2
return new UserNotAuthenticatedException();
- case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
+ case KeymasterDefs.KM_ERROR_KEY_EXPIRED: // -25
return new KeyExpiredException();
- case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
+ case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID: // -2
return new KeyNotYetValidException();
- case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
- case OP_AUTH_NEEDED:
+ case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED: // -26
+ case OP_AUTH_NEEDED: // 15
{
// We now need to determine whether the key/operation can become usable if user
// authentication is performed, or whether it can never become usable again.
@@ -879,7 +882,7 @@ public class KeyStore {
// None of the key's SIDs can ever be authenticated
return new KeyPermanentlyInvalidatedException();
}
- case UNINITIALIZED:
+ case UNINITIALIZED: // 3
return new KeyPermanentlyInvalidatedException();
default:
return new InvalidKeyException("Keystore operation failed", e);
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index 09b3b9b523b4..419eb24e1cc1 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -243,13 +243,7 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
// Check that user authentication related parameters are acceptable. This method
// will throw an IllegalStateException if there are issues (e.g., secure lock screen
// not set up).
- KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
- spec.isUserAuthenticationRequired(),
- spec.getUserAuthenticationValidityDurationSeconds(),
- spec.isUserAuthenticationValidWhileOnBody(),
- spec.isInvalidatedByBiometricEnrollment(),
- GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
- spec.isUserConfirmationRequired());
+ KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), spec);
} catch (IllegalStateException | IllegalArgumentException e) {
throw new InvalidAlgorithmParameterException(e);
}
@@ -285,16 +279,7 @@ public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes);
args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterPaddings);
args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
- KeymasterUtils.addUserAuthArgs(args,
- spec.isUserAuthenticationRequired(),
- spec.getUserAuthenticationValidityDurationSeconds(),
- spec.isUserAuthenticationValidWhileOnBody(),
- spec.isInvalidatedByBiometricEnrollment(),
- GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
- spec.isUserConfirmationRequired());
- if (spec.isTrustedUserPresenceRequired()) {
- args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
- }
+ KeymasterUtils.addUserAuthArgs(args, spec);
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
args,
mKeymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index e33e3cd4e92b..d68a33de2c61 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -344,13 +344,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
// Check that user authentication related parameters are acceptable. This method
// will throw an IllegalStateException if there are issues (e.g., secure lock screen
// not set up).
- KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
- mSpec.isUserAuthenticationRequired(),
- mSpec.getUserAuthenticationValidityDurationSeconds(),
- mSpec.isUserAuthenticationValidWhileOnBody(),
- mSpec.isInvalidatedByBiometricEnrollment(),
- GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
- mSpec.isUserConfirmationRequired());
+ KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), mSpec);
} catch (IllegalArgumentException | IllegalStateException e) {
throw new InvalidAlgorithmParameterException(e);
}
@@ -541,13 +535,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterSignaturePaddings);
args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
- KeymasterUtils.addUserAuthArgs(args,
- mSpec.isUserAuthenticationRequired(),
- mSpec.getUserAuthenticationValidityDurationSeconds(),
- mSpec.isUserAuthenticationValidWhileOnBody(),
- mSpec.isInvalidatedByBiometricEnrollment(),
- GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
- mSpec.isUserConfirmationRequired());
+ KeymasterUtils.addUserAuthArgs(args, mSpec);
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
mSpec.getKeyValidityForOriginationEnd());
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index 05cc74a0bec9..fc86ca0443b0 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -497,13 +497,7 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterEncryptionPaddings);
importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING,
KeyProperties.SignaturePadding.allToKeymaster(spec.getSignaturePaddings()));
- KeymasterUtils.addUserAuthArgs(importArgs,
- spec.isUserAuthenticationRequired(),
- spec.getUserAuthenticationValidityDurationSeconds(),
- spec.isUserAuthenticationValidWhileOnBody(),
- spec.isInvalidatedByBiometricEnrollment(),
- spec.getBoundToSpecificSecureUserId(),
- spec.isUserConfirmationRequired());
+ KeymasterUtils.addUserAuthArgs(importArgs, spec);
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
spec.getKeyValidityStart());
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
@@ -700,13 +694,7 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
int[] keymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
params.getEncryptionPaddings());
args.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
- KeymasterUtils.addUserAuthArgs(args,
- params.isUserAuthenticationRequired(),
- params.getUserAuthenticationValidityDurationSeconds(),
- params.isUserAuthenticationValidWhileOnBody(),
- params.isInvalidatedByBiometricEnrollment(),
- params.getBoundToSpecificSecureUserId(),
- params.isUserConfirmationRequired());
+ KeymasterUtils.addUserAuthArgs(args, params);
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
args,
keymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index da23c70f58bb..d0814c6f2f93 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.KeyguardManager;
import android.hardware.fingerprint.FingerprintManager;
+import android.security.GateKeeper;
import android.security.KeyStore;
import android.text.TextUtils;
@@ -232,7 +233,7 @@ import javax.security.auth.x500.X500Principal;
* key = (SecretKey) keyStore.getKey("key2", null);
* }</pre>
*/
-public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
+public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAuthArgs {
private static final X500Principal DEFAULT_CERT_SUBJECT = new X500Principal("CN=fake");
private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1");
@@ -265,6 +266,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
private final boolean mInvalidatedByBiometricEnrollment;
private final boolean mIsStrongBoxBacked;
private final boolean mUserConfirmationRequired;
+ private final boolean mUnlockedDeviceRequired;
/**
* @hide should be built with Builder
@@ -295,7 +297,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
boolean userAuthenticationValidWhileOnBody,
boolean invalidatedByBiometricEnrollment,
boolean isStrongBoxBacked,
- boolean userConfirmationRequired) {
+ boolean userConfirmationRequired,
+ boolean unlockedDeviceRequired) {
if (TextUtils.isEmpty(keyStoreAlias)) {
throw new IllegalArgumentException("keyStoreAlias must not be empty");
}
@@ -344,6 +347,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
mIsStrongBoxBacked = isStrongBoxBacked;
mUserConfirmationRequired = userConfirmationRequired;
+ mUnlockedDeviceRequired = unlockedDeviceRequired;
}
/**
@@ -669,6 +673,22 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
}
/**
+ * Returns {@code true} if the key cannot be used unless the device screen is unlocked.
+ *
+ * @see Builder#SetUnlockedDeviceRequired(boolean)
+ */
+ public boolean isUnlockedDeviceRequired() {
+ return mUnlockedDeviceRequired;
+ }
+
+ /**
+ * @hide
+ */
+ public long getBoundToSpecificSecureUserId() {
+ return GateKeeper.INVALID_SECURE_USER_ID;
+ }
+
+ /**
* Builder of {@link KeyGenParameterSpec} instances.
*/
public final static class Builder {
@@ -699,6 +719,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
private boolean mInvalidatedByBiometricEnrollment = true;
private boolean mIsStrongBoxBacked = false;
private boolean mUserConfirmationRequired;
+ private boolean mUnlockedDeviceRequired = false;
/**
* Creates a new instance of the {@code Builder}.
@@ -1267,6 +1288,18 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
}
/**
+ * Sets whether the keystore requires the screen to be unlocked before allowing decryption
+ * using this key. If this is set to {@code true}, any attempt to decrypt using this key
+ * while the screen is locked will fail. A locked device requires a PIN, password,
+ * fingerprint, or other trusted factor to access.
+ */
+ @NonNull
+ public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) {
+ mUnlockedDeviceRequired = unlockedDeviceRequired;
+ return this;
+ }
+
+ /**
* Builds an instance of {@code KeyGenParameterSpec}.
*/
@NonNull
@@ -1297,7 +1330,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
mUserAuthenticationValidWhileOnBody,
mInvalidatedByBiometricEnrollment,
mIsStrongBoxBacked,
- mUserConfirmationRequired);
+ mUserConfirmationRequired,
+ mUnlockedDeviceRequired);
}
}
}
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index b5b328192f21..7f8259b89962 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -212,7 +212,7 @@ import javax.crypto.Mac;
* ...
* }</pre>
*/
-public final class KeyProtection implements ProtectionParameter {
+public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
private final Date mKeyValidityStart;
private final Date mKeyValidityForOriginationEnd;
private final Date mKeyValidityForConsumptionEnd;
@@ -229,6 +229,8 @@ public final class KeyProtection implements ProtectionParameter {
private final long mBoundToSecureUserId;
private final boolean mCriticalToDeviceEncryption;
private final boolean mUserConfirmationRequired;
+ private final boolean mTrustedUserPresenceRequired;
+ private final boolean mUnlockedDeviceRequired;
private KeyProtection(
Date keyValidityStart,
@@ -242,11 +244,13 @@ public final class KeyProtection implements ProtectionParameter {
boolean randomizedEncryptionRequired,
boolean userAuthenticationRequired,
int userAuthenticationValidityDurationSeconds,
+ boolean trustedUserPresenceRequired,
boolean userAuthenticationValidWhileOnBody,
boolean invalidatedByBiometricEnrollment,
long boundToSecureUserId,
boolean criticalToDeviceEncryption,
- boolean userConfirmationRequired) {
+ boolean userConfirmationRequired,
+ boolean unlockedDeviceRequired) {
mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
@@ -265,6 +269,8 @@ public final class KeyProtection implements ProtectionParameter {
mBoundToSecureUserId = boundToSecureUserId;
mCriticalToDeviceEncryption = criticalToDeviceEncryption;
mUserConfirmationRequired = userConfirmationRequired;
+ mTrustedUserPresenceRequired = trustedUserPresenceRequired;
+ mUnlockedDeviceRequired = unlockedDeviceRequired;
}
/**
@@ -437,6 +443,14 @@ public final class KeyProtection implements ProtectionParameter {
}
/**
+ * Returns {@code true} if the key is authorized to be used only if a test of user presence has
+ * been performed between the {@code Signature.initSign()} and {@code Signature.sign()} calls.
+ */
+ public boolean isTrustedUserPresenceRequired() {
+ return mTrustedUserPresenceRequired;
+ }
+
+ /**
* Returns {@code true} if the key will be de-authorized when the device is removed from the
* user's body. This option has no effect on keys that don't have an authentication validity
* duration, and has no effect if the device lacks an on-body sensor.
@@ -494,6 +508,15 @@ public final class KeyProtection implements ProtectionParameter {
}
/**
+ * Returns {@code true} if the key cannot be used unless the device screen is unlocked.
+ *
+ * @see Builder#SetRequireDeviceUnlocked(boolean)
+ */
+ public boolean isUnlockedDeviceRequired() {
+ return mUnlockedDeviceRequired;
+ }
+
+ /**
* Builder of {@link KeyProtection} instances.
*/
public final static class Builder {
@@ -512,6 +535,9 @@ public final class KeyProtection implements ProtectionParameter {
private boolean mUserAuthenticationValidWhileOnBody;
private boolean mInvalidatedByBiometricEnrollment = true;
private boolean mUserConfirmationRequired;
+ private boolean mTrustedUserPresenceRequired = false;
+ private boolean mUnlockedDeviceRequired = false;
+
private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID;
private boolean mCriticalToDeviceEncryption = false;
@@ -811,6 +837,16 @@ public final class KeyProtection implements ProtectionParameter {
}
/**
+ * Sets whether a test of user presence is required to be performed between the
+ * {@code Signature.initSign()} and {@code Signature.sign()} method calls.
+ */
+ @NonNull
+ public Builder setTrustedUserPresenceRequired(boolean required) {
+ mTrustedUserPresenceRequired = required;
+ return this;
+ }
+
+ /**
* Sets whether the key will remain authorized only until the device is removed from the
* user's body up to the limit of the authentication validity period (see
* {@link #setUserAuthenticationValidityDurationSeconds} and
@@ -892,6 +928,18 @@ public final class KeyProtection implements ProtectionParameter {
}
/**
+ * Sets whether the keystore requires the screen to be unlocked before allowing decryption
+ * using this key. If this is set to {@code true}, any attempt to decrypt using this key
+ * while the screen is locked will fail. A locked device requires a PIN, password,
+ * fingerprint, or other trusted factor to access.
+ */
+ @NonNull
+ public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) {
+ mUnlockedDeviceRequired = unlockedDeviceRequired;
+ return this;
+ }
+
+ /**
* Builds an instance of {@link KeyProtection}.
*
* @throws IllegalArgumentException if a required field is missing
@@ -910,11 +958,13 @@ public final class KeyProtection implements ProtectionParameter {
mRandomizedEncryptionRequired,
mUserAuthenticationRequired,
mUserAuthenticationValidityDurationSeconds,
+ mTrustedUserPresenceRequired,
mUserAuthenticationValidWhileOnBody,
mInvalidatedByBiometricEnrollment,
mBoundToSecureUserId,
mCriticalToDeviceEncryption,
- mUserConfirmationRequired);
+ mUserConfirmationRequired,
+ mUnlockedDeviceRequired);
}
}
}
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index 4e28601f17a1..5bd0e7406ff9 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -18,6 +18,7 @@ package android.security.keystore;
import android.util.Log;
import android.hardware.fingerprint.FingerprintManager;
+import android.os.UserHandle;
import android.security.GateKeeper;
import android.security.KeyStore;
import android.security.keymaster.KeymasterArguments;
@@ -101,22 +102,27 @@ public abstract class KeymasterUtils {
* require user authentication.
*/
public static void addUserAuthArgs(KeymasterArguments args,
- boolean userAuthenticationRequired,
- int userAuthenticationValidityDurationSeconds,
- boolean userAuthenticationValidWhileOnBody,
- boolean invalidatedByBiometricEnrollment,
- long boundToSpecificSecureUserId,
- boolean userConfirmationRequired) {
- if (userConfirmationRequired) {
+ UserAuthArgs spec) {
+ if (spec.isTrustedUserPresenceRequired()) {
+ args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
+ }
+
+ if (spec.isUserConfirmationRequired()) {
args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED);
}
- if (!userAuthenticationRequired) {
+ if (spec.isUnlockedDeviceRequired()) {
+ args.addBoolean(KeymasterDefs.KM_TAG_UNLOCKED_DEVICE_REQUIRED);
+ // Once keymaster is properly ignoring this tag, it should be added to every auth list
+ args.addUnsignedInt(KeymasterDefs.KM_TAG_USER_ID, UserHandle.getCallingUserId());
+ }
+
+ if (!spec.isUserAuthenticationRequired()) {
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
return;
}
- if (userAuthenticationValidityDurationSeconds == -1) {
+ if (spec.getUserAuthenticationValidityDurationSeconds() == -1) {
// Every use of this key needs to be authorized by the user. This currently means
// fingerprint-only auth.
FingerprintManager fingerprintManager =
@@ -132,9 +138,9 @@ public abstract class KeymasterUtils {
}
long sid;
- if (boundToSpecificSecureUserId != GateKeeper.INVALID_SECURE_USER_ID) {
- sid = boundToSpecificSecureUserId;
- } else if (invalidatedByBiometricEnrollment) {
+ if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
+ sid = spec.getBoundToSpecificSecureUserId();
+ } else if (spec.isInvalidatedByBiometricEnrollment()) {
// The fingerprint-only SID will change on fingerprint enrollment or removal of all,
// enrolled fingerprints, invalidating the key.
sid = fingerprintOnlySid;
@@ -147,14 +153,14 @@ public abstract class KeymasterUtils {
args.addUnsignedLong(
KeymasterDefs.KM_TAG_USER_SECURE_ID, KeymasterArguments.toUint64(sid));
args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, KeymasterDefs.HW_AUTH_FINGERPRINT);
- if (userAuthenticationValidWhileOnBody) {
+ if (spec.isUserAuthenticationValidWhileOnBody()) {
throw new ProviderException("Key validity extension while device is on-body is not "
+ "supported for keys requiring fingerprint authentication");
}
} else {
long sid;
- if (boundToSpecificSecureUserId != GateKeeper.INVALID_SECURE_USER_ID) {
- sid = boundToSpecificSecureUserId;
+ if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
+ sid = spec.getBoundToSpecificSecureUserId();
} else {
// The key is authorized for use for the specified amount of time after the user has
// authenticated. Whatever unlocks the secure lock screen should authorize this key.
@@ -165,8 +171,8 @@ public abstract class KeymasterUtils {
args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
KeymasterDefs.HW_AUTH_PASSWORD | KeymasterDefs.HW_AUTH_FINGERPRINT);
args.addUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
- userAuthenticationValidityDurationSeconds);
- if (userAuthenticationValidWhileOnBody) {
+ spec.getUserAuthenticationValidityDurationSeconds());
+ if (spec.isUserAuthenticationValidWhileOnBody()) {
args.addBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
}
}
diff --git a/keystore/java/android/security/keystore/UserAuthArgs.java b/keystore/java/android/security/keystore/UserAuthArgs.java
new file mode 100644
index 000000000000..3a7017ecaa88
--- /dev/null
+++ b/keystore/java/android/security/keystore/UserAuthArgs.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+/**
+ * @hide
+ *
+ * This is an interface to encapsulate the user authentication arguments that
+ * are passed to KeymasterUtils.addUserAuthArgs. Classes that represent
+ * authorization characteristics for new or imported keys can implement this
+ * interface to be passed to that method.
+ */
+public interface UserAuthArgs {
+
+ boolean isUserAuthenticationRequired();
+ int getUserAuthenticationValidityDurationSeconds();
+ boolean isUserAuthenticationValidWhileOnBody();
+ boolean isInvalidatedByBiometricEnrollment();
+ boolean isTrustedUserPresenceRequired();
+ boolean isUnlockedDeviceRequired();
+ boolean isUserConfirmationRequired();
+ long getBoundToSpecificSecureUserId();
+
+}
diff --git a/libs/incident/Android.mk b/libs/incident/Android.mk
index b63400f14609..08c834699f40 100644
--- a/libs/incident/Android.mk
+++ b/libs/incident/Android.mk
@@ -33,6 +33,7 @@ LOCAL_SRC_FILES := \
../../core/java/android/os/IIncidentManager.aidl \
../../core/java/android/os/IIncidentReportStatusListener.aidl \
proto/android/os/header.proto \
+ proto/android/os/metadata.proto \
src/IncidentReportArgs.cpp
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
diff --git a/libs/incident/proto/android/os/metadata.proto b/libs/incident/proto/android/os/metadata.proto
new file mode 100644
index 000000000000..a1e89b0dbf98
--- /dev/null
+++ b/libs/incident/proto/android/os/metadata.proto
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+option java_multiple_files = true;
+
+package android.os;
+
+// This field contains internal metadata associated with an incident report,
+// such as the section ids and privacy policy specs from caller as well as how long
+// and how many bytes a section takes, etc.
+message IncidentMetadata {
+
+ // privacy level of the incident report.
+ enum Destination {
+ AUTOMATIC = 0;
+ EXPLICIT = 1;
+ LOCAL = 2;
+ }
+ optional Destination dest = 1;
+
+ optional int32 request_size = 2;
+
+ optional bool use_dropbox = 3;
+
+ // stats of each section taken in this incident report.
+ message SectionStats {
+ // section id.
+ optional int32 id = 1;
+ // if the section is successfully taken.
+ optional bool success = 2;
+ // number of bytes in the report after filtering.
+ optional int32 report_size_bytes = 3;
+ // the total duration to execute the section.
+ optional int64 exec_duration_ms = 4;
+
+ // number of bytes dumped from the section directly.
+ optional int32 dump_size_bytes = 5;
+ // duration of the dump takes.
+ optional int64 dump_duration_ms = 6;
+ // true if the section timed out.
+ optional bool timed_out = 7;
+ // true if the section is truncated.
+ optional bool is_truncated = 8;
+
+ // Next Tag: 9
+ }
+ repeated SectionStats sections = 4;
+}
+
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index d194796ec1c5..7d2ad9125f40 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -23,6 +23,7 @@ import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
@@ -30,6 +31,7 @@ import android.annotation.SystemService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -63,6 +65,7 @@ import java.util.List;
* location will be obfuscated to a coarse level of accuracy.
*/
@SystemService(Context.LOCATION_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_LOCATION)
public class LocationManager {
private static final String TAG = "LocationManager";
diff --git a/media/OWNERS b/media/OWNERS
new file mode 100644
index 000000000000..8f405e98545b
--- /dev/null
+++ b/media/OWNERS
@@ -0,0 +1,4 @@
+elaurent@google.com
+etalvala@google.com
+lajos@google.com
+marcone@google.com
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 0be54ec2b2d9..9ff964b3f0d4 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -16,6 +16,7 @@
package android.media;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -65,6 +66,8 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+
/**
* AudioManager provides access to volume and ringer mode control.
@@ -4864,6 +4867,114 @@ public class AudioManager {
}
}
+
+ /**
+ * @hide
+ * Abstract class to receive event notification about audioserver process state.
+ */
+ @SystemApi
+ public abstract static class AudioServerStateCallback {
+ public void onAudioServerDown() { }
+ public void onAudioServerUp() { }
+ }
+
+ private Executor mAudioServerStateExec;
+ private AudioServerStateCallback mAudioServerStateCb;
+ private final Object mAudioServerStateCbLock = new Object();
+
+ private final IAudioServerStateDispatcher mAudioServerStateDispatcher =
+ new IAudioServerStateDispatcher.Stub() {
+ @Override
+ public void dispatchAudioServerStateChange(boolean state) {
+ Executor exec;
+ AudioServerStateCallback cb;
+
+ synchronized (mAudioServerStateCbLock) {
+ exec = mAudioServerStateExec;
+ cb = mAudioServerStateCb;
+ }
+
+ if ((exec == null) || (cb == null)) {
+ return;
+ }
+ if (state) {
+ exec.execute(() -> cb.onAudioServerUp());
+ } else {
+ exec.execute(() -> cb.onAudioServerDown());
+ }
+ }
+ };
+
+ /**
+ * @hide
+ * Registers a callback for notification of audio server state changes.
+ * @param executor {@link Executor} to handle the callbacks
+ * @param stateCallback the callback to receive the audio server state changes
+ * To remove the callabck, pass a null reference for both executor and stateCallback.
+ */
+ @SystemApi
+ public void setAudioServerStateCallback(@NonNull Executor executor,
+ @NonNull AudioServerStateCallback stateCallback) {
+ if (stateCallback == null) {
+ throw new IllegalArgumentException("Illegal null AudioServerStateCallback");
+ }
+ if (executor == null) {
+ throw new IllegalArgumentException(
+ "Illegal null Executor for the AudioServerStateCallback");
+ }
+
+ synchronized (mAudioServerStateCbLock) {
+ if (mAudioServerStateCb != null) {
+ throw new IllegalStateException(
+ "setAudioServerStateCallback called with already registered callabck");
+ }
+ final IAudioService service = getService();
+ try {
+ service.registerAudioServerStateDispatcher(mAudioServerStateDispatcher);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ mAudioServerStateExec = executor;
+ mAudioServerStateCb = stateCallback;
+ }
+ }
+
+ /**
+ * @hide
+ * Unregisters the callback for notification of audio server state changes.
+ */
+ @SystemApi
+ public void clearAudioServerStateCallback() {
+ synchronized (mAudioServerStateCbLock) {
+ if (mAudioServerStateCb != null) {
+ final IAudioService service = getService();
+ try {
+ service.unregisterAudioServerStateDispatcher(
+ mAudioServerStateDispatcher);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ mAudioServerStateExec = null;
+ mAudioServerStateCb = null;
+ }
+ }
+
+ /**
+ * @hide
+ * Checks if native audioservice is running or not.
+ * @return true if native audioservice runs, false otherwise.
+ */
+ @SystemApi
+ public boolean isAudioServerRunning() {
+ final IAudioService service = getService();
+ try {
+ return service.isAudioServerRunning();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
//---------------------------------------------------------
// Inner classes
//--------------------
diff --git a/media/java/android/media/DataSourceDesc.java b/media/java/android/media/DataSourceDesc.java
index 73fad7ad4bf3..6dff07f96092 100644
--- a/media/java/android/media/DataSourceDesc.java
+++ b/media/java/android/media/DataSourceDesc.java
@@ -30,6 +30,8 @@ import com.android.internal.util.Preconditions;
import java.io.FileDescriptor;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.net.CookieHandler;
+import java.net.CookieManager;
import java.net.HttpCookie;
import java.util.ArrayList;
@@ -433,10 +435,22 @@ public final class DataSourceDesc {
* @param cookies the cookies to be sent together with the request
* @return the same Builder instance.
* @throws NullPointerException if context or uri is null.
+ * @throws IllegalArgumentException if the cookie handler is not of CookieManager type
+ * when cookies are provided.
*/
public Builder setDataSource(@NonNull Context context, @NonNull Uri uri,
@Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies) {
+ Preconditions.checkNotNull(context, "context cannot be null");
Preconditions.checkNotNull(uri);
+ if (cookies != null) {
+ CookieHandler cookieHandler = CookieHandler.getDefault();
+ if (cookieHandler != null && !(cookieHandler instanceof CookieManager)) {
+ throw new IllegalArgumentException(
+ "The cookie handler has to be of CookieManager type "
+ + "when cookies are provided.");
+ }
+ }
+
resetDataSource();
mType = TYPE_URI;
mUri = uri;
diff --git a/core/java/android/security/keymaster/ExportResult.aidl b/media/java/android/media/IAudioServerStateDispatcher.aidl
index 17486531a3f0..2bc90eaf1780 100644
--- a/core/java/android/security/keymaster/ExportResult.aidl
+++ b/media/java/android/media/IAudioServerStateDispatcher.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -14,7 +14,15 @@
* limitations under the License.
*/
-package android.security.keymaster;
+package android.media;
-/* @hide */
-parcelable ExportResult cpp_header "keystore/ExportResult.h";
+/**
+ * AIDL for the AudioService to signal audio server state changes
+ *
+ * {@hide}
+ */
+oneway interface IAudioServerStateDispatcher {
+
+ void dispatchAudioServerStateChange(boolean state);
+
+}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 4c37014b7397..05ba4c35c21d 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -24,10 +24,12 @@ import android.media.AudioRecordingConfiguration;
import android.media.AudioRoutesInfo;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioRoutesObserver;
+import android.media.IAudioServerStateDispatcher;
import android.media.IPlaybackConfigDispatcher;
import android.media.IRecordingConfigDispatcher;
import android.media.IRingtonePlayer;
import android.media.IVolumeController;
+import android.media.IVolumeController;
import android.media.PlayerBase;
import android.media.VolumePolicy;
import android.media.audiopolicy.AudioPolicyConfig;
@@ -208,6 +210,12 @@ interface IAudioService {
oneway void setFocusRequestResultFromExtPolicy(in AudioFocusInfo afi, int requestResult,
in IAudioPolicyCallback pcb);
+ void registerAudioServerStateDispatcher(IAudioServerStateDispatcher asd);
+
+ oneway void unregisterAudioServerStateDispatcher(IAudioServerStateDispatcher asd);
+
+ boolean isAudioServerRunning();
+
// WARNING: read warning at top of file, new methods that need to be used by native
// code via IAudioManager.h need to be added to the top section.
}
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index e331b2cbf645..2f3d972ae6e2 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -804,19 +804,6 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener
public abstract DataSourceDesc editPlaylistItem(int index, DataSourceDesc dsd);
/**
- * Prepares the player for playback, synchronously.
- *
- * After setting the datasource and the display surface, you need to either
- * call prepare() or prepareAsync(). For files, it is OK to call prepare(),
- * which blocks until MediaPlayer2 is ready for playback.
- *
- * @throws IOException if source can not be accessed
- * @throws IllegalStateException if it is called in an invalid state
- * @hide
- */
- public void prepare() throws IOException { }
-
- /**
* Prepares the player for playback, asynchronously.
*
* After setting the datasource and the display surface, you need to
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index b805eb4482cd..1b21b5bc2afd 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -137,7 +137,7 @@ import java.util.Vector;
* {@link #getVideoWidth()}, {@link #setAudioAttributes(AudioAttributes)},
* {@link #setLooping(boolean)},
* {@link #setVolume(float, float)}, {@link #pause()}, {@link #play()},
- * {@link #seekTo(long, int)}, {@link #prepare()} or
+ * {@link #seekTo(long, int)} or
* {@link #prepareAsync()} in the <em>Idle</em> state for both cases. If any of these
* methods is called right after a MediaPlayer2 object is constructed,
* the user supplied callback method OnErrorListener.onError() won't be
@@ -184,7 +184,7 @@ import java.util.Vector;
* register a OnErrorListener to look out for error notifications from
* the internal player engine.</li>
* <li>IllegalStateException is
- * thrown to prevent programming errors such as calling {@link #prepare()},
+ * thrown to prevent programming errors such as calling
* {@link #prepareAsync()}, {@link #setDataSource(DataSourceDesc)}, or
* {@code setPlaylist} methods in an invalid state. </li>
* </ul>
@@ -206,15 +206,11 @@ import java.util.Vector;
* <li>A MediaPlayer2 object must first enter the <em>Prepared</em> state
* before playback can be started.
* <ul>
- * <li>There are two ways (synchronous vs.
- * asynchronous) that the <em>Prepared</em> state can be reached:
- * either a call to {@link #prepare()} (synchronous) which
- * transfers the object to the <em>Prepared</em> state once the method call
- * returns, or a call to {@link #prepareAsync()} (asynchronous) which
- * first transfers the object to the <em>Preparing</em> state after the
+ * <li>{@link #prepareAsync()} first transfers the object to the
+ * <em>Preparing</em> state after the
* call returns (which occurs almost right way) while the internal
* player engine continues working on the rest of preparation work
- * until the preparation work completes. When the preparation completes or when {@link #prepare()} call returns,
+ * until the preparation work completes. When the preparation completes,
* the internal player engine then calls a user supplied callback method,
* onPrepared() of the EventCallback interface, if an
* EventCallback is registered beforehand via {@link
@@ -224,7 +220,7 @@ import java.util.Vector;
* of calling any method with side effect while a MediaPlayer2 object is
* in the <em>Preparing</em> state is undefined.</li>
* <li>An IllegalStateException is
- * thrown if {@link #prepare()} or {@link #prepareAsync()} is called in
+ * thrown if {@link #prepareAsync()} is called in
* any other state.</li>
* <li>While in the <em>Prepared</em> state, properties
* such as audio/sound volume, screenOnWhilePlaying, looping can be
@@ -395,7 +391,7 @@ import java.util.Vector;
* <td>{Error}</p></td>
* <td>Successful invoke of this method does not change the state. In order for the
* target audio attributes type to become effective, this method must be called before
- * prepare() or prepareAsync().</p></td></tr>
+ * prepareAsync().</p></td></tr>
* <tr><td>setAudioSessionId </p></td>
* <td>{Idle} </p></td>
* <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted,
@@ -409,7 +405,7 @@ import java.util.Vector;
* <td>{Error}</p></td>
* <td>Successful invoke of this method does not change the state. In order for the
* target audio stream type to become effective, this method must be called before
- * prepare() or prepareAsync().</p></td></tr>
+ * prepareAsync().</p></td></tr>
* <tr><td>setAuxEffectSendLevel </p></td>
* <td>any</p></td>
* <td>{} </p></td>
@@ -561,9 +557,12 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
private boolean mBypassInterruptionPolicy;
private final CloseGuard mGuard = CloseGuard.get();
+ private final Object mPlLock = new Object();
private List<DataSourceDesc> mPlaylist;
- private int mPLCurrentIndex = 0;
- private int mPLNextIndex = -1;
+ private int mPlCurrentIndex = 0;
+ private int mPlNextIndex = -1;
+ private int mPlNextSourceState = NEXT_SOURCE_STATE_INIT;
+ private boolean mPlNextSourcePlayPending = false;
private int mLoopingMode = LOOPING_MODE_NONE;
// Modular DRM
@@ -605,6 +604,11 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
native_setup(new WeakReference<MediaPlayer2Impl>(this));
}
+ private static final int NEXT_SOURCE_STATE_ERROR = -1;
+ private static final int NEXT_SOURCE_STATE_INIT = 0;
+ private static final int NEXT_SOURCE_STATE_PREPARING = 1;
+ private static final int NEXT_SOURCE_STATE_PREPARED = 2;
+
/*
* Update the MediaPlayer2Impl SurfaceTexture.
* Call after setting a new display surface.
@@ -774,10 +778,13 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
@Override
public void setDataSource(@NonNull DataSourceDesc dsd) throws IOException {
Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
- mPlaylist = Collections.synchronizedList(new ArrayList<DataSourceDesc>(1));
- mPlaylist.add(dsd);
- mPLCurrentIndex = 0;
- setDataSourcePriv(dsd);
+ synchronized (mPlLock) {
+ mPlaylist = Collections.synchronizedList(new ArrayList<DataSourceDesc>(1));
+ mPlaylist.add(dsd);
+ mPlCurrentIndex = 0;
+ mPlNextIndex = -1;
+ handleDataSource(true /* isCurrent */, dsd);
+ }
}
/**
@@ -787,10 +794,12 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
*/
@Override
public DataSourceDesc getCurrentDataSource() {
- if (mPlaylist == null) {
- return null;
+ synchronized (mPlLock) {
+ if (mPlaylist == null) {
+ return null;
+ }
+ return mPlaylist.get(mPlCurrentIndex);
}
- return mPlaylist.get(mPLCurrentIndex);
}
/**
@@ -826,11 +835,14 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
startIndex = pl.size() - 1;
}
- mPlaylist = Collections.synchronizedList(new ArrayList(pl));
- mPLCurrentIndex = startIndex;
- setDataSourcePriv(mPlaylist.get(startIndex));
- // TODO: handle the preparation of next source in the play list.
- // It should be processed after current source is prepared.
+ synchronized (mPlLock) {
+ mPlaylist = Collections.synchronizedList(new ArrayList(pl));
+ mPlCurrentIndex = startIndex;
+ handleDataSource(true /* isCurrent */, mPlaylist.get(startIndex));
+ // TODO: handle the preparation of next source in the play list.
+ // It should be processed after current source is prepared.
+ mPlNextIndex = getNextIndex_l();
+ }
}
/**
@@ -840,10 +852,12 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
*/
@Override
public List<DataSourceDesc> getPlaylist() {
- if (mPlaylist == null) {
- return null;
+ synchronized (mPlLock) {
+ if (mPlaylist == null) {
+ return null;
+ }
+ return new ArrayList(mPlaylist);
}
- return new ArrayList(mPlaylist);
}
/**
@@ -855,19 +869,21 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
*/
@Override
public void setCurrentPlaylistItem(int index) {
- if (mPlaylist == null) {
- throw new IllegalArgumentException("play list has not been set yet.");
- }
- if (index < 0 || index >= mPlaylist.size()) {
- throw new IndexOutOfBoundsException("index is out of play list range.");
- }
+ synchronized (mPlLock) {
+ if (mPlaylist == null) {
+ throw new IllegalArgumentException("play list has not been set yet.");
+ }
+ if (index < 0 || index >= mPlaylist.size()) {
+ throw new IndexOutOfBoundsException("index is out of play list range.");
+ }
- if (index == mPLCurrentIndex) {
- return;
- }
+ if (index == mPlCurrentIndex) {
+ return;
+ }
- // TODO: in playing state, stop current source and start to play source of index.
- mPLCurrentIndex = index;
+ // TODO: in playing state, stop current source and start to play source of index.
+ mPlCurrentIndex = index;
+ }
}
/**
@@ -879,19 +895,21 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
*/
@Override
public void setNextPlaylistItem(int index) {
- if (mPlaylist == null) {
- throw new IllegalArgumentException("play list has not been set yet.");
- }
- if (index < 0 || index >= mPlaylist.size()) {
- throw new IndexOutOfBoundsException("index is out of play list range.");
- }
+ synchronized (mPlLock) {
+ if (mPlaylist == null) {
+ throw new IllegalArgumentException("play list has not been set yet.");
+ }
+ if (index < 0 || index >= mPlaylist.size()) {
+ throw new IndexOutOfBoundsException("index is out of play list range.");
+ }
- if (index == mPLNextIndex) {
- return;
- }
+ if (index == mPlNextIndex) {
+ return;
+ }
- // TODO: prepare the new next-to-be-played DataSourceDesc
- mPLNextIndex = index;
+ // TODO: prepare the new next-to-be-played DataSourceDesc
+ mPlNextIndex = index;
+ }
}
/**
@@ -901,7 +919,9 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
*/
@Override
public int getCurrentPlaylistItemIndex() {
- return mPLCurrentIndex;
+ synchronized (mPlLock) {
+ return mPlCurrentIndex;
+ }
}
/**
@@ -920,12 +940,15 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
&& mode != LOOPING_MODE_SHUFFLE) {
throw new IllegalArgumentException("mode is not supported.");
}
- mLoopingMode = mode;
- if (mPlaylist == null) {
- return;
- }
- // TODO: handle the new mode if necessary.
+ synchronized (mPlLock) {
+ mLoopingMode = mode;
+ if (mPlaylist == null) {
+ return;
+ }
+
+ // TODO: handle the new mode if necessary.
+ }
}
/**
@@ -935,7 +958,9 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
*/
@Override
public int getLoopingMode() {
- return mPLCurrentIndex;
+ synchronized (mPlLock) {
+ return mPlCurrentIndex;
+ }
}
/**
@@ -946,10 +971,12 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
*/
@Override
public void movePlaylistItem(int indexFrom, int indexTo) {
- if (mPlaylist == null) {
- throw new IllegalArgumentException("play list has not been set yet.");
+ synchronized (mPlLock) {
+ if (mPlaylist == null) {
+ throw new IllegalArgumentException("play list has not been set yet.");
+ }
+ // TODO: move the DataSourceDesc from indexFrom to indexTo.
}
- // TODO: move the DataSourceDesc from indexFrom to indexTo.
}
/**
@@ -964,14 +991,16 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
*/
@Override
public DataSourceDesc removePlaylistItem(int index) {
- if (mPlaylist == null) {
- throw new IllegalArgumentException("play list has not been set yet.");
- }
+ synchronized (mPlLock) {
+ if (mPlaylist == null) {
+ throw new IllegalArgumentException("play list has not been set yet.");
+ }
- DataSourceDesc oldDsd = mPlaylist.remove(index);
- // TODO: if index == mPLCurrentIndex, stop current source and move to next one.
- // if index == mPLNextIndex, prepare the new next-to-be-played source.
- return oldDsd;
+ DataSourceDesc oldDsd = mPlaylist.remove(index);
+ // TODO: if index == mPlCurrentIndex, stop current source and move to next one.
+ // if index == mPlNextIndex, prepare the new next-to-be-played source.
+ return oldDsd;
+ }
}
/**
@@ -990,26 +1019,28 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
public void addPlaylistItem(int index, DataSourceDesc dsd) {
Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
- if (mPlaylist == null) {
- if (index == 0) {
- mPlaylist = Collections.synchronizedList(new ArrayList<DataSourceDesc>());
- mPlaylist.add(dsd);
- mPLCurrentIndex = 0;
- return;
+ synchronized (mPlLock) {
+ if (mPlaylist == null) {
+ if (index == 0) {
+ mPlaylist = Collections.synchronizedList(new ArrayList<DataSourceDesc>());
+ mPlaylist.add(dsd);
+ mPlCurrentIndex = 0;
+ return;
+ }
+ throw new IllegalArgumentException("index should be 0 for first DataSourceDesc.");
}
- throw new IllegalArgumentException("index should be 0 for first DataSourceDesc.");
- }
- long id = dsd.getId();
- for (DataSourceDesc pldsd : mPlaylist) {
- if (id == pldsd.getId()) {
- throw new IllegalArgumentException("Id of dsd already exists in the play list.");
+ long id = dsd.getId();
+ for (DataSourceDesc pldsd : mPlaylist) {
+ if (id == pldsd.getId()) {
+ throw new IllegalArgumentException("Id of dsd already exists in the play list.");
+ }
}
- }
- mPlaylist.add(index, dsd);
- if (index <= mPLCurrentIndex) {
- ++mPLCurrentIndex;
+ mPlaylist.add(index, dsd);
+ if (index <= mPlCurrentIndex) {
+ ++mPlCurrentIndex;
+ }
}
}
@@ -1036,42 +1067,62 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
Preconditions.checkNotNull(mPlaylist, "the play list cannot be null");
long id = dsd.getId();
- for (int i = 0; i < mPlaylist.size(); ++i) {
- if (i == index) {
- continue;
- }
- if (id == mPlaylist.get(i).getId()) {
- throw new IllegalArgumentException("Id of dsd already exists in the play list.");
+ synchronized (mPlLock) {
+ for (int i = 0; i < mPlaylist.size(); ++i) {
+ if (i == index) {
+ continue;
+ }
+ if (id == mPlaylist.get(i).getId()) {
+ throw new IllegalArgumentException(
+ "Id of dsd already exists in the play list.");
+ }
}
+
+ // TODO: if needed, stop playback of current source, and start new dsd.
+ DataSourceDesc oldDsd = mPlaylist.set(index, dsd);
+ return mPlaylist.set(index, dsd);
}
+ }
- // TODO: if needed, stop playback of current source, and start new dsd.
- DataSourceDesc oldDsd = mPlaylist.set(index, dsd);
- return mPlaylist.set(index, dsd);
+ // Called with mPlLock acquired.
+ // TODO: support all looping modes
+ private int getNextIndex_l() {
+ if (mPlaylist.size() <= 1) {
+ return -1;
+ }
+ int index = mPlCurrentIndex + 1;
+ if (index >= mPlaylist.size()) {
+ index = 0;
+ }
+ return index;
}
- private void setDataSourcePriv(@NonNull DataSourceDesc dsd) throws IOException {
+ private void handleDataSource(boolean isCurrent, @NonNull DataSourceDesc dsd)
+ throws IOException {
Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
switch (dsd.getType()) {
case DataSourceDesc.TYPE_CALLBACK:
- setDataSourcePriv(dsd.getId(),
- dsd.getMedia2DataSource());
+ handleDataSource(isCurrent,
+ dsd.getId(),
+ dsd.getMedia2DataSource());
break;
case DataSourceDesc.TYPE_FD:
- setDataSourcePriv(dsd.getId(),
- dsd.getFileDescriptor(),
- dsd.getFileDescriptorOffset(),
- dsd.getFileDescriptorLength());
+ handleDataSource(isCurrent,
+ dsd.getId(),
+ dsd.getFileDescriptor(),
+ dsd.getFileDescriptorOffset(),
+ dsd.getFileDescriptorLength());
break;
case DataSourceDesc.TYPE_URI:
- setDataSourcePriv(dsd.getId(),
- dsd.getUriContext(),
- dsd.getUri(),
- dsd.getUriHeaders(),
- dsd.getUriCookies());
+ handleDataSource(isCurrent,
+ dsd.getId(),
+ dsd.getUriContext(),
+ dsd.getUri(),
+ dsd.getUriHeaders(),
+ dsd.getUriCookies());
break;
default:
@@ -1098,66 +1149,59 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
* @throws NullPointerException if context or uri is null
* @throws IOException if uri has a file scheme and an I/O error occurs
*/
- private void setDataSourcePriv(long srcId, @NonNull Context context, @NonNull Uri uri,
+ private void handleDataSource(
+ boolean isCurrent, long srcId,
+ @NonNull Context context, @NonNull Uri uri,
@Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies)
throws IOException {
- if (context == null) {
- throw new NullPointerException("context param can not be null.");
- }
-
- if (uri == null) {
- throw new NullPointerException("uri param can not be null.");
- }
-
- if (cookies != null) {
- CookieHandler cookieHandler = CookieHandler.getDefault();
- if (cookieHandler != null && !(cookieHandler instanceof CookieManager)) {
- throw new IllegalArgumentException("The cookie handler has to be of CookieManager "
- + "type when cookies are provided.");
- }
- }
-
// The context and URI usually belong to the calling user. Get a resolver for that user
// and strip out the userId from the URI if present.
final ContentResolver resolver = context.getContentResolver();
final String scheme = uri.getScheme();
final String authority = ContentProvider.getAuthorityWithoutUserId(uri.getAuthority());
if (ContentResolver.SCHEME_FILE.equals(scheme)) {
- setDataSourcePriv(srcId, uri.getPath(), null, null);
+ handleDataSource(isCurrent, srcId, uri.getPath(), null, null);
return;
- } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
+ }
+
+ if (ContentResolver.SCHEME_CONTENT.equals(scheme)
&& Settings.AUTHORITY.equals(authority)) {
// Try cached ringtone first since the actual provider may not be
// encryption aware, or it may be stored on CE media storage
final int type = RingtoneManager.getDefaultType(uri);
final Uri cacheUri = RingtoneManager.getCacheForType(type, context.getUserId());
final Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(context, type);
- if (attemptDataSource(srcId, resolver, cacheUri)) {
+ if (attemptDataSource(isCurrent, srcId, resolver, cacheUri)) {
return;
- } else if (attemptDataSource(srcId, resolver, actualUri)) {
+ }
+ if (attemptDataSource(isCurrent, srcId, resolver, actualUri)) {
return;
- } else {
- setDataSourcePriv(srcId, uri.toString(), headers, cookies);
}
+ handleDataSource(isCurrent, srcId, uri.toString(), headers, cookies);
} else {
// Try requested Uri locally first, or fallback to media server
- if (attemptDataSource(srcId, resolver, uri)) {
+ if (attemptDataSource(isCurrent, srcId, resolver, uri)) {
return;
- } else {
- setDataSourcePriv(srcId, uri.toString(), headers, cookies);
}
+ handleDataSource(isCurrent, srcId, uri.toString(), headers, cookies);
}
}
- private boolean attemptDataSource(long srcId, ContentResolver resolver, Uri uri) {
+ private boolean attemptDataSource(
+ boolean isCurrent, long srcId, ContentResolver resolver, Uri uri) {
try (AssetFileDescriptor afd = resolver.openAssetFileDescriptor(uri, "r")) {
if (afd.getDeclaredLength() < 0) {
- setDataSourcePriv(srcId, afd.getFileDescriptor(), 0, DataSourceDesc.LONG_MAX);
+ handleDataSource(isCurrent,
+ srcId,
+ afd.getFileDescriptor(),
+ 0,
+ DataSourceDesc.LONG_MAX);
} else {
- setDataSourcePriv(srcId,
- afd.getFileDescriptor(),
- afd.getStartOffset(),
- afd.getDeclaredLength());
+ handleDataSource(isCurrent,
+ srcId,
+ afd.getFileDescriptor(),
+ afd.getStartOffset(),
+ afd.getDeclaredLength());
}
return true;
} catch (NullPointerException | SecurityException | IOException ex) {
@@ -1166,10 +1210,10 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
}
}
- private void setDataSourcePriv(
- long srcId, String path, Map<String, String> headers, List<HttpCookie> cookies)
- throws IOException, IllegalArgumentException, SecurityException, IllegalStateException
- {
+ private void handleDataSource(
+ boolean isCurrent, long srcId,
+ String path, Map<String, String> headers, List<HttpCookie> cookies)
+ throws IOException {
String[] keys = null;
String[] values = null;
@@ -1184,19 +1228,20 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
++i;
}
}
- setDataSourcePriv(srcId, path, keys, values, cookies);
+ handleDataSource(isCurrent, srcId, path, keys, values, cookies);
}
- private void setDataSourcePriv(long srcId, String path, String[] keys, String[] values,
- List<HttpCookie> cookies)
- throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
+ private void handleDataSource(boolean isCurrent, long srcId,
+ String path, String[] keys, String[] values, List<HttpCookie> cookies)
+ throws IOException {
final Uri uri = Uri.parse(path);
final String scheme = uri.getScheme();
if ("file".equals(scheme)) {
path = uri.getPath();
} else if (scheme != null) {
// handle non-file sources
- nativeSetDataSource(
+ nativeHandleDataSourceUrl(
+ isCurrent,
srcId,
Media2HTTPService.createHTTPService(path, cookies),
path,
@@ -1209,16 +1254,17 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
if (file.exists()) {
FileInputStream is = new FileInputStream(file);
FileDescriptor fd = is.getFD();
- setDataSourcePriv(srcId, fd, 0, DataSourceDesc.LONG_MAX);
+ handleDataSource(isCurrent, srcId, fd, 0, DataSourceDesc.LONG_MAX);
is.close();
} else {
- throw new IOException("setDataSourcePriv failed.");
+ throw new IOException("handleDataSource failed.");
}
}
- private native void nativeSetDataSource(
- long srcId, Media2HTTPService httpService, String path, String[] keys, String[] values)
- throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
+ private native void nativeHandleDataSourceUrl(
+ boolean isCurrent, long srcId,
+ Media2HTTPService httpService, String path, String[] keys, String[] values)
+ throws IOException;
/**
* Sets the data source (FileDescriptor) to use. The FileDescriptor must be
@@ -1229,53 +1275,92 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
* @throws IllegalArgumentException if fd is not a valid FileDescriptor
* @throws IOException if fd can not be read
*/
- private void setDataSourcePriv(long srcId, FileDescriptor fd, long offset, long length)
- throws IOException {
- _setDataSource(srcId, fd, offset, length);
+ private void handleDataSource(
+ boolean isCurrent, long srcId,
+ FileDescriptor fd, long offset, long length) throws IOException {
+ nativeHandleDataSourceFD(isCurrent, srcId, fd, offset, length);
}
- private native void _setDataSource(long srcId, FileDescriptor fd, long offset, long length)
- throws IOException;
+ private native void nativeHandleDataSourceFD(boolean isCurrent, long srcId,
+ FileDescriptor fd, long offset, long length) throws IOException;
/**
* @throws IllegalStateException if it is called in an invalid state
* @throws IllegalArgumentException if dataSource is not a valid Media2DataSource
*/
- private void setDataSourcePriv(long srcId, Media2DataSource dataSource) {
- _setDataSource(srcId, dataSource);
+ private void handleDataSource(boolean isCurrent, long srcId, Media2DataSource dataSource) {
+ nativeHandleDataSourceCallback(isCurrent, srcId, dataSource);
}
- private native void _setDataSource(long srcId, Media2DataSource dataSource);
+ private native void nativeHandleDataSourceCallback(
+ boolean isCurrent, long srcId, Media2DataSource dataSource);
- /**
- * Prepares the player for playback, synchronously.
- *
- * After setting the datasource and the display surface, you need to either
- * call prepare() or prepareAsync(). For files, it is OK to call prepare(),
- * which blocks until MediaPlayer2 is ready for playback.
- *
- * @throws IOException if source can not be accessed
- * @throws IllegalStateException if it is called in an invalid state
- * @hide
- */
- @Override
- public void prepare() throws IOException {
- _prepare();
- scanInternalSubtitleTracks();
+ // This function shall be called with |mPlLock| acquired.
+ private void prepareNextDataSource_l() {
+ if (mPlNextIndex < 0 || mPlNextSourceState != NEXT_SOURCE_STATE_INIT) {
+ // There is no next source or it's in preparing or prepared state.
+ return;
+ }
- // DrmInfo, if any, has been resolved by now.
- synchronized (mDrmLock) {
- mDrmInfoResolved = true;
+ try {
+ mPlNextSourceState = NEXT_SOURCE_STATE_PREPARING;
+ handleDataSource(false /* isCurrent */, mPlaylist.get(mPlNextIndex));
+ } catch (Exception e) {
+ Message msg2 = mEventHandler.obtainMessage(
+ MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
+ final long nextSrcId = mPlaylist.get(mPlNextIndex).getId();
+ mEventHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mEventHandler.handleMessage(msg2, nextSrcId);
+ }
+ });
}
}
- private native void _prepare() throws IOException, IllegalStateException;
+ // This function shall be called with |mPlLock| acquired.
+ private void playNextDataSource_l() {
+ if (mPlNextIndex < 0) {
+ return;
+ }
+
+ if (mPlNextSourceState == NEXT_SOURCE_STATE_PREPARED) {
+ // Switch to next source only when it's in prepared state.
+ mPlCurrentIndex = mPlNextIndex;
+ mPlNextIndex = getNextIndex_l();
+ mPlNextSourceState = NEXT_SOURCE_STATE_INIT;
+ mPlNextSourcePlayPending = false;
+
+ long srcId = mPlaylist.get(mPlCurrentIndex).getId();
+ try {
+ nativePlayNextDataSource(srcId);
+ } catch (Exception e) {
+ Message msg2 = mEventHandler.obtainMessage(
+ MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
+ mEventHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mEventHandler.handleMessage(msg2, srcId);
+ }
+ });
+ }
+
+ // Wait for MEDIA2_INFO_STARTED_AS_NEXT to prepare next source.
+ } else {
+ if (mPlNextSourceState == NEXT_SOURCE_STATE_INIT) {
+ prepareNextDataSource_l();
+ }
+ mPlNextSourcePlayPending = true;
+ }
+ }
+
+ private native void nativePlayNextDataSource(long srcId);
/**
* Prepares the player for playback, asynchronously.
*
* After setting the datasource and the display surface, you need to either
- * call prepare() or prepareAsync(). For streams, you should call prepareAsync(),
+ * call prepareAsync(). For streams, you should call prepareAsync(),
* which returns immediately, rather than blocking until enough data has been
* buffered.
*
@@ -1925,7 +2010,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
/**
* Resets the MediaPlayer2 to its uninitialized state. After calling
* this method, you will have to initialize it again by setting the
- * data source and calling prepare().
+ * data source and calling prepareAsync().
*/
@Override
public void reset() {
@@ -2000,7 +2085,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
/**
* Sets the audio attributes for this MediaPlayer2.
* See {@link AudioAttributes} for how to build and configure an instance of this class.
- * You must call this method before {@link #prepare()} or {@link #prepareAsync()} in order
+ * You must call this method before {@link #prepareAsync()} in order
* for the audio attributes to become effective thereafter.
* @param attributes a non-null set of audio attributes
* @throws IllegalArgumentException if the attributes are null or invalid.
@@ -3089,6 +3174,19 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
sendMessage(msg2);
}
+ synchronized (mPlLock) {
+ Log.i(TAG, "MEDIA_PREPARED: srcId=" + srcId
+ + ", currentIndex=" + mPlCurrentIndex + ", nextIndex=" + mPlNextIndex);
+ if (mPlCurrentIndex >= 0 && srcId == mPlaylist.get(mPlCurrentIndex).getId()) {
+ prepareNextDataSource_l();
+ } else if (mPlNextIndex >= 0 && srcId == mPlaylist.get(mPlNextIndex).getId()) {
+ mPlNextSourceState = NEXT_SOURCE_STATE_PREPARED;
+ if (mPlNextSourcePlayPending) {
+ playNextDataSource_l();
+ }
+ }
+ }
+
synchronized (mEventCbLock) {
for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onInfo(
@@ -3127,6 +3225,14 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
return;
case MEDIA_PLAYBACK_COMPLETE:
+ synchronized (mPlLock) {
+ if (mPlCurrentIndex >= 0 && srcId == mPlaylist.get(mPlCurrentIndex).getId()) {
+ Log.i(TAG, "MEDIA_PLAYBACK_COMPLETE: srcId=" + srcId
+ + ", currentIndex=" + mPlCurrentIndex + ", nextIndex=" + mPlNextIndex);
+ playNextDataSource_l();
+ }
+ }
+
synchronized (mEventCbLock) {
for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onInfo(
@@ -3209,6 +3315,12 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
case MEDIA_INFO:
switch (msg.arg1) {
+ case MEDIA_INFO_STARTED_AS_NEXT:
+ if (mPlCurrentIndex >= 0 && srcId == mPlaylist.get(mPlCurrentIndex).getId()) {
+ prepareNextDataSource_l();
+ }
+ break;
+
case MEDIA_INFO_VIDEO_TRACK_LAGGING:
Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")");
break;
@@ -3517,7 +3629,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
/**
* Retrieves the DRM Info associated with the current source
*
- * @throws IllegalStateException if called before prepare()
+ * @throws IllegalStateException if called before prepareAsync()
*/
@Override
public DrmInfo getDrmInfo() {
@@ -3568,7 +3680,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
* @param uuid The UUID of the crypto scheme. If not known beforehand, it can be retrieved
* from the source through {@code getDrmInfo} or registering a {@code onDrmInfoListener}.
*
- * @throws IllegalStateException if called before prepare(), or the DRM was
+ * @throws IllegalStateException if called before prepareAsync(), or the DRM was
* prepared already
* @throws UnsupportedSchemeException if the crypto scheme is not supported
* @throws ResourceBusyException if required DRM resources are in use
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 823410f6bb76..9ad5cd93e1e2 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -17,6 +17,7 @@
package android.media;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.app.ActivityThread;
import android.hardware.Camera;
@@ -278,6 +279,7 @@ public class MediaRecorder implements AudioRouting
* third-party applications.
* </p>
*/
+ @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT)
public static final int REMOTE_SUBMIX = 8;
/** Microphone audio source tuned for unprocessed (raw) sound if available, behaves like
@@ -303,6 +305,7 @@ public class MediaRecorder implements AudioRouting
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_HOTWORD)
public static final int HOTWORD = 1999;
}
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 219063564132..343bbdaf27d5 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -400,6 +400,7 @@ public class AudioPolicy {
new AudioAttributes.Builder()
.setInternalCapturePreset(MediaRecorder.AudioSource.REMOTE_SUBMIX)
.addTag(addressForTag(mix))
+ .addTag(AudioRecord.SUBMIX_FIXED_VOLUME)
.build(),
mixFormat,
AudioRecord.getMinBufferSize(mix.getFormat().getSampleRate(),
diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java
index a015732ddfdd..dee94c681e87 100644
--- a/media/java/android/media/midi/MidiManager.java
+++ b/media/java/android/media/midi/MidiManager.java
@@ -16,9 +16,11 @@
package android.media.midi;
+import android.annotation.RequiresFeature;
import android.annotation.SystemService;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.Bundle;
@@ -32,6 +34,7 @@ import java.util.concurrent.ConcurrentHashMap;
* This class is the public application interface to the MIDI service.
*/
@SystemService(Context.MIDI_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_MIDI)
public final class MidiManager {
private static final String TAG = "MidiManager";
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index b8184a0789b6..b8d01c44348b 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -119,7 +119,8 @@ public final class MediaSession {
private final ISession mBinder;
private final CallbackStub mCbStub;
- private CallbackMessageHandler mCallbackHandler;
+ // Do not change the name of mCallback. Support lib accesses this by using reflection.
+ private CallbackMessageHandler mCallback;
private VolumeProvider mVolumeProvider;
private PlaybackState mPlaybackState;
@@ -194,13 +195,13 @@ public final class MediaSession {
*/
public void setCallback(@Nullable Callback callback, @Nullable Handler handler) {
synchronized (mLock) {
- if (mCallbackHandler != null) {
+ if (mCallback != null) {
// We're updating the callback, clear the session from the old one.
- mCallbackHandler.mCallback.mSession = null;
- mCallbackHandler.removeCallbacksAndMessages(null);
+ mCallback.mCallback.mSession = null;
+ mCallback.removeCallbacksAndMessages(null);
}
if (callback == null) {
- mCallbackHandler = null;
+ mCallback = null;
return;
}
if (handler == null) {
@@ -209,7 +210,7 @@ public final class MediaSession {
callback.mSession = this;
CallbackMessageHandler msgHandler = new CallbackMessageHandler(handler.getLooper(),
callback);
- mCallbackHandler = msgHandler;
+ mCallback = msgHandler;
}
}
@@ -634,8 +635,8 @@ public final class MediaSession {
private void postToCallback(int what, Object obj, Bundle extras) {
synchronized (mLock) {
- if (mCallbackHandler != null) {
- mCallbackHandler.post(what, obj, extras);
+ if (mCallback != null) {
+ mCallback.post(what, obj, extras);
}
}
}
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index d7f51d4e6986..3518392d30b6 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -20,7 +20,7 @@
#include "android_media_MediaDrm.h"
#include "android_media_MediaMetricsJNI.h"
-
+#include "android_os_Parcel.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/Log.h"
#include "android_os_Parcel.h"
@@ -29,12 +29,16 @@
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
+#include <binder/PersistableBundle.h>
#include <cutils/properties.h>
#include <media/IDrm.h>
#include <media/IMediaDrmService.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaErrors.h>
+using ::android::os::PersistableBundle;
+
+
namespace android {
#define FIND_CLASS(var, className) \
@@ -57,6 +61,10 @@ namespace android {
var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! (var), "Unable to find static method " fieldName);
+#define GET_STATIC_OBJECT_FIELD(var, clazz, fieldName) \
+ var = env->GetStaticObjectField(clazz, fieldName); \
+ LOG_FATAL_IF(! (var), "Unable to find static object field " fieldName);
+
struct RequestFields {
jfieldID data;
@@ -170,10 +178,58 @@ struct fields_t {
jclass hashmapClassId;
jclass arraylistClassId;
jclass stringClassId;
+ jobject bundleCreator;
+ jmethodID createFromParcelId;
+ jclass parcelCreatorClassId;
};
static fields_t gFields;
+namespace {
+
+// Helper function to convert a native PersistableBundle to a Java
+// PersistableBundle.
+jobject nativeToJavaPersistableBundle(JNIEnv *env, jobject thiz,
+ PersistableBundle* nativeBundle) {
+ if (env == NULL || thiz == NULL || nativeBundle == NULL) {
+ ALOGE("Unexpected NULL parmeter");
+ return NULL;
+ }
+
+ // Create a Java parcel with the native parcel data.
+ // Then create a new PersistableBundle with that parcel as a parameter.
+ jobject jParcel = android::createJavaParcelObject(env);
+ if (jParcel == NULL) {
+ ALOGE("Failed to create a Java Parcel.");
+ return NULL;
+ }
+
+ android::Parcel* nativeParcel = android::parcelForJavaObject(env, jParcel);
+ if (nativeParcel == NULL) {
+ ALOGE("Failed to get the native Parcel.");
+ return NULL;
+ }
+
+ android::status_t result = nativeBundle->writeToParcel(nativeParcel);
+ nativeParcel->setDataPosition(0);
+ if (result != android::OK) {
+ ALOGE("Failed to write nativeBundle to Parcel: %d.", result);
+ return NULL;
+ }
+
+ jobject newBundle = env->CallObjectMethod(gFields.bundleCreator,
+ gFields.createFromParcelId,
+ jParcel);
+ if (newBundle == NULL) {
+ ALOGE("Failed to create a new PersistableBundle "
+ "from the createFromParcel call.");
+ }
+
+ return newBundle;
+}
+
+} // namespace anonymous
+
// ----------------------------------------------------------------------------
// ref-counted object for callbacks
class JNIDrmListener: public DrmListener
@@ -713,6 +769,19 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) {
GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
+ // Metrics-related fields and classes.
+ FIND_CLASS(clazz, "android/os/PersistableBundle");
+ jfieldID bundleCreatorId;
+ GET_STATIC_FIELD_ID(bundleCreatorId, clazz, "CREATOR",
+ "Landroid/os/Parcelable$Creator;");
+ jobject bundleCreator;
+ GET_STATIC_OBJECT_FIELD(bundleCreator, clazz, bundleCreatorId);
+ gFields.bundleCreator = static_cast<jobject>(env->NewGlobalRef(bundleCreator));
+ FIND_CLASS(clazz, "android/os/Parcelable$Creator");
+ GET_METHOD_ID(gFields.createFromParcelId, clazz, "createFromParcel",
+ "(Landroid/os/Parcel;)Ljava/lang/Object;");
+ gFields.parcelCreatorClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
+
FIND_CLASS(clazz, "java/util/ArrayList");
GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
@@ -1656,19 +1725,14 @@ android_media_MediaDrm_native_getMetrics(JNIEnv *env, jobject thiz)
}
// Retrieve current metrics snapshot from drm.
- MediaAnalyticsItem item ;
- status_t err = drm->getMetrics(&item);
+ PersistableBundle metrics;
+ status_t err = drm->getMetrics(&metrics);
if (err != OK) {
ALOGE("getMetrics failed: %d", (int)err);
return (jobject) NULL;
}
- jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, &item, NULL);
- if (mybundle == NULL) {
- ALOGE("getMetrics metric conversion failed");
- }
-
- return mybundle;
+ return nativeToJavaPersistableBundle(env, thiz, &metrics);
}
static jbyteArray android_media_MediaDrm_signRSANative(
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 51bc33069802..5a0081a146f2 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -273,9 +273,9 @@ static void process_media_player_call(
}
static void
-android_media_MediaPlayer2_setDataSourceAndHeaders(
- JNIEnv *env, jobject thiz, jlong srcId, jobject httpServiceObj, jstring path,
- jobjectArray keys, jobjectArray values) {
+android_media_MediaPlayer2_handleDataSourceUrl(
+ JNIEnv *env, jobject thiz, jboolean isCurrent, jlong srcId,
+ jobject httpServiceObj, jstring path, jobjectArray keys, jobjectArray values) {
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL) {
@@ -292,10 +292,10 @@ android_media_MediaPlayer2_setDataSourceAndHeaders(
if (tmp == NULL) { // Out of memory
return;
}
- ALOGV("setDataSourceAndHeaders: path %s, srcId %lld", tmp, (long long)srcId);
+ ALOGV("handleDataSourceUrl: path %s, srcId %lld", tmp, (long long)srcId);
if (strncmp(tmp, "content://", 10) == 0) {
- ALOGE("setDataSourceAndHeaders: content scheme is not supported in native code");
+ ALOGE("handleDataSourceUrl: content scheme is not supported in native code");
jniThrowException(env, "java/io/IOException",
"content scheme is not supported in native code");
return;
@@ -321,14 +321,20 @@ android_media_MediaPlayer2_setDataSourceAndHeaders(
}
dsd->mHttpService = httpService;
- process_media_player_call(
- env, thiz, mp->setDataSource(dsd), "java/io/IOException",
- "setDataSourceAndHeaders failed." );
+ status_t err;
+ if (isCurrent) {
+ err = mp->setDataSource(dsd);
+ } else {
+ err = mp->prepareNextDataSource(dsd);
+ }
+ process_media_player_call(env, thiz, err,
+ "java/io/IOException", "handleDataSourceUrl failed." );
}
static void
-android_media_MediaPlayer2_setDataSourceFD(
- JNIEnv *env, jobject thiz, jlong srcId, jobject fileDescriptor, jlong offset, jlong length)
+android_media_MediaPlayer2_handleDataSourceFD(
+ JNIEnv *env, jobject thiz, jboolean isCurrent, jlong srcId,
+ jobject fileDescriptor, jlong offset, jlong length)
{
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
@@ -341,14 +347,14 @@ android_media_MediaPlayer2_setDataSourceFD(
return;
}
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- ALOGV("setDataSourceFD: srcId=%lld, fd=%d (%s), offset=%lld, length=%lld",
+ ALOGV("handleDataSourceFD: srcId=%lld, fd=%d (%s), offset=%lld, length=%lld",
(long long)srcId, fd, nameForFd(fd).c_str(), (long long)offset, (long long)length);
struct stat sb;
int ret = fstat(fd, &sb);
if (ret != 0) {
- ALOGE("setDataSourceFD: fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
- jniThrowException(env, "java/io/IOException", "setDataSourceFD failed fstat");
+ ALOGE("handleDataSourceFD: fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
+ jniThrowException(env, "java/io/IOException", "handleDataSourceFD failed fstat");
return;
}
@@ -359,14 +365,14 @@ android_media_MediaPlayer2_setDataSourceFD(
ALOGV("st_size = %llu", static_cast<unsigned long long>(sb.st_size));
if (offset >= sb.st_size) {
- ALOGE("setDataSourceFD: offset is out of range");
+ ALOGE("handleDataSourceFD: offset is out of range");
jniThrowException(env, "java/lang/IllegalArgumentException",
- "setDataSourceFD failed, offset is out of range.");
+ "handleDataSourceFD failed, offset is out of range.");
return;
}
if (offset + length > sb.st_size) {
length = sb.st_size - offset;
- ALOGV("setDataSourceFD: adjusted length = %lld", (long long)length);
+ ALOGV("handleDataSourceFD: adjusted length = %lld", (long long)length);
}
sp<DataSourceDesc> dsd = new DataSourceDesc();
@@ -375,13 +381,20 @@ android_media_MediaPlayer2_setDataSourceFD(
dsd->mFD = fd;
dsd->mFDOffset = offset;
dsd->mFDLength = length;
- process_media_player_call(env, thiz, mp->setDataSource(dsd),
- "java/io/IOException", "setDataSourceFD failed." );
+
+ status_t err;
+ if (isCurrent) {
+ err = mp->setDataSource(dsd);
+ } else {
+ err = mp->prepareNextDataSource(dsd);
+ }
+ process_media_player_call(env, thiz, err,
+ "java/io/IOException", "handleDataSourceFD failed." );
}
static void
-android_media_MediaPlayer2_setDataSourceCallback(
- JNIEnv *env, jobject thiz, jlong srcId, jobject dataSource)
+android_media_MediaPlayer2_handleDataSourceCallback(
+ JNIEnv *env, jobject thiz, jboolean isCurrent, jlong srcId, jobject dataSource)
{
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
@@ -398,8 +411,15 @@ android_media_MediaPlayer2_setDataSourceCallback(
dsd->mId = srcId;
dsd->mType = DataSourceDesc::TYPE_CALLBACK;
dsd->mCallbackSource = callbackDataSource;
- process_media_player_call(env, thiz, mp->setDataSource(dsd),
- "java/lang/RuntimeException", "setDataSourceCallback failed." );
+
+ status_t err;
+ if (isCurrent) {
+ err = mp->setDataSource(dsd);
+ } else {
+ err = mp->prepareNextDataSource(dsd);
+ }
+ process_media_player_call(env, thiz, err,
+ "java/lang/RuntimeException", "handleDataSourceCallback failed." );
}
static sp<ANativeWindowWrapper>
@@ -503,20 +523,16 @@ android_media_MediaPlayer2_setBufferingParams(JNIEnv *env, jobject thiz, jobject
}
static void
-android_media_MediaPlayer2_prepare(JNIEnv *env, jobject thiz)
+android_media_MediaPlayer2_playNextDataSource(JNIEnv *env, jobject thiz, jlong srcId)
{
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
- if (mp == NULL ) {
+ if (mp == NULL) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return;
}
- // Handle the case where the display surface was set before the mp was
- // initialized. We try again to make it stick.
- sp<ANativeWindowWrapper> st = getVideoSurfaceTexture(env, thiz);
- mp->setVideoSurfaceTexture(st);
-
- process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
+ process_media_player_call(env, thiz, mp->playNextDataSource((int64_t)srcId),
+ "java/io/IOException", "playNextDataSource failed." );
}
static void
@@ -1449,18 +1465,25 @@ static void android_media_MediaPlayer2_native_on_stream_data_request(JNIEnv *env
static const JNINativeMethod gMethods[] = {
{
- "nativeSetDataSource",
- "(JLandroid/media/Media2HTTPService;Ljava/lang/String;[Ljava/lang/String;"
+ "nativeHandleDataSourceUrl",
+ "(ZJLandroid/media/Media2HTTPService;Ljava/lang/String;[Ljava/lang/String;"
"[Ljava/lang/String;)V",
- (void *)android_media_MediaPlayer2_setDataSourceAndHeaders
+ (void *)android_media_MediaPlayer2_handleDataSourceUrl
},
-
- {"_setDataSource", "(JLjava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer2_setDataSourceFD},
- {"_setDataSource", "(JLandroid/media/Media2DataSource;)V",(void *)android_media_MediaPlayer2_setDataSourceCallback },
+ {
+ "nativeHandleDataSourceFD",
+ "(ZJLjava/io/FileDescriptor;JJ)V",
+ (void *)android_media_MediaPlayer2_handleDataSourceFD
+ },
+ {
+ "nativeHandleDataSourceCallback",
+ "(ZJLandroid/media/Media2DataSource;)V",
+ (void *)android_media_MediaPlayer2_handleDataSourceCallback
+ },
+ {"nativePlayNextDataSource", "(J)V", (void *)android_media_MediaPlayer2_playNextDataSource},
{"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer2_setVideoSurface},
{"getBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer2_getBufferingParams},
{"setBufferingParams", "(Landroid/media/BufferingParams;)V", (void *)android_media_MediaPlayer2_setBufferingParams},
- {"_prepare", "()V", (void *)android_media_MediaPlayer2_prepare},
{"prepareAsync", "()V", (void *)android_media_MediaPlayer2_prepareAsync},
{"_start", "()V", (void *)android_media_MediaPlayer2_start},
{"_stop", "()V", (void *)android_media_MediaPlayer2_stop},
diff --git a/native/android/OWNERS b/native/android/OWNERS
new file mode 100644
index 000000000000..11d4be43571e
--- /dev/null
+++ b/native/android/OWNERS
@@ -0,0 +1,11 @@
+set noparent
+
+per-file libandroid_net.map.txt=ek@google.com
+per-file libandroid_net.map.txt=jchalard@google.com
+per-file libandroid_net.map.txt=lorenzo@google.com
+per-file libandroid_net.map.txt=satk@google.com
+
+per-file net.c=ek@google.com
+per-file net.c=jchalard@google.com
+per-file net.c=lorenzo@google.com
+per-file net.c=satk@google.com
diff --git a/packages/CarrierDefaultApp/OWNERS b/packages/CarrierDefaultApp/OWNERS
new file mode 100644
index 000000000000..7057ce6cb6fe
--- /dev/null
+++ b/packages/CarrierDefaultApp/OWNERS
@@ -0,0 +1,12 @@
+tgunn@google.com
+breadley@google.com
+hallliu@google.com
+rgreenwalt@google.com
+mpq@google.com
+amitmahajan@google.com
+fionaxu@google.com
+jackyu@google.com
+jminjie@google.com
+satk@google.com
+shuoq@google.com
+refuhoo@google.com \ No newline at end of file
diff --git a/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml
index e399fb170759..9f546525942b 100644
--- a/packages/DefaultContainerService/AndroidManifest.xml
+++ b/packages/DefaultContainerService/AndroidManifest.xml
@@ -6,9 +6,6 @@
<uses-permission android:name="android.permission.ASEC_DESTROY"/>
<uses-permission android:name="android.permission.ASEC_MOUNT_UNMOUNT"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <!-- Used to improve MeasureUtils performance on emulated storage, and to
- view storage for all users -->
- <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 44f68eca49a3..d73a5d73e5bf 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -3117,6 +3117,8 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
private final Consumer<String> mCallback;
+ private boolean mIsTransformationStarted;
+
public DocumentTransformer(Context context, PrintJobInfo printJob,
MutexFileProvider fileProvider, PrintAttributes attributes,
Consumer<String> callback) {
@@ -3144,29 +3146,35 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
- final IPdfEditor editor = IPdfEditor.Stub.asInterface(service);
- new AsyncTask<Void, Void, String>() {
- @Override
- protected String doInBackground(Void... params) {
- // It's OK to access the data members as they are
- // final and this code is the last one to touch
- // them as shredding is the very last step, so the
- // UI is not interactive at this point.
- try {
- doTransform(editor);
- updatePrintJob();
- return null;
- } catch (IOException | RemoteException | IllegalStateException e) {
- return e.toString();
+ // We might get several onServiceConnected if the service crashes and restarts.
+ // mIsTransformationStarted makes sure that we only try once.
+ if (!mIsTransformationStarted) {
+ final IPdfEditor editor = IPdfEditor.Stub.asInterface(service);
+ new AsyncTask<Void, Void, String>() {
+ @Override
+ protected String doInBackground(Void... params) {
+ // It's OK to access the data members as they are
+ // final and this code is the last one to touch
+ // them as shredding is the very last step, so the
+ // UI is not interactive at this point.
+ try {
+ doTransform(editor);
+ updatePrintJob();
+ return null;
+ } catch (IOException | RemoteException | IllegalStateException e) {
+ return e.toString();
+ }
}
- }
- @Override
- protected void onPostExecute(String error) {
- mContext.unbindService(DocumentTransformer.this);
- mCallback.accept(error);
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ @Override
+ protected void onPostExecute(String error) {
+ mContext.unbindService(DocumentTransformer.this);
+ mCallback.accept(error);
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+
+ mIsTransformationStarted = true;
+ }
}
@Override
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
index 7c2e55f35cde..cf73aacb9b55 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
@@ -285,6 +285,11 @@ public final class SelectPrinterActivity extends Activity implements
final int position = ((AdapterContextMenuInfo) menuInfo).position;
PrinterInfo printer = (PrinterInfo) mListView.getAdapter().getItem(position);
+ // Printer is null if this is a context menu for the "add printer" entry
+ if (printer == null) {
+ return;
+ }
+
menu.setHeaderTitle(printer.getName());
// Add the select menu item if applicable.
diff --git a/packages/SettingsLib/res/drawable/ic_bt_hearing_aid.xml b/packages/SettingsLib/res/drawable/ic_bt_hearing_aid.xml
new file mode 100644
index 000000000000..e14c99b61e2f
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_bt_hearing_aid.xml
@@ -0,0 +1,24 @@
+<!--
+ 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.
+-->
+<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="#FF000000"
+ android:pathData="M17,20c-0.29,0 -0.56,-0.06 -0.76,-0.15 -0.71,-0.37 -1.21,-0.88 -1.71,-2.38 -0.51,-1.56 -1.47,-2.29 -2.39,-3 -0.79,-0.61 -1.61,-1.24 -2.32,-2.53C9.29,10.98 9,9.93 9,9c0,-2.8 2.2,-5 5,-5s5,2.2 5,5h2c0,-3.93 -3.07,-7 -7,-7S7,5.07 7,9c0,1.26 0.38,2.65 1.07,3.9 0.91,1.65 1.98,2.48 2.85,3.15 0.81,0.62 1.39,1.07 1.71,2.05 0.6,1.82 1.37,2.84 2.73,3.55 0.51,0.23 1.07,0.35 1.64,0.35 2.21,0 4,-1.79 4,-4h-2c0,1.1 -0.9,2 -2,2zM7.64,2.64L6.22,1.22C4.23,3.21 3,5.96 3,9s1.23,5.79 3.22,7.78l1.41,-1.41C6.01,13.74 5,11.49 5,9s1.01,-4.74 2.64,-6.36zM11.5,9c0,1.38 1.12,2.5 2.5,2.5s2.5,-1.12 2.5,-2.5 -1.12,-2.5 -2.5,-2.5 -2.5,1.12 -2.5,2.5z"/>
+</vector>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index e6f4ec6e8979..c78f4541384a 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -177,6 +177,11 @@
<!-- Bluetooth settings. Similar to bluetooth_profile_a2dp_high_quality, but used when the device supports high quality audio but we don't know which codec that will be used. -->
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec">HD audio</string>
+ <!-- Bluetooth settings. The user-visible string that is used whenever referring to the Hearing Aid profile. -->
+ <string name="bluetooth_profile_hearing_aid">Hearing Aid</string>
+ <!-- Bluetooth settings. Connection options screen. The summary for the Hearing Aid checkbox preference when Hearing Aid is connected. -->
+ <string name="bluetooth_hearing_aid_profile_summary_connected">Connected to Hearing Aid</string>
+
<!-- Bluetooth settings. Connection options screen. The summary for the A2DP checkbox preference when A2DP is connected. -->
<string name="bluetooth_a2dp_profile_summary_connected">Connected to media audio</string>
<!-- Bluetooth settings. Connection options screen. The summary for the headset checkbox preference when headset is connected. -->
@@ -214,6 +219,8 @@
for the HID checkbox preference that describes how checking it
will set the HID profile as preferred. -->
<string name="bluetooth_hid_profile_summary_use_for">Use for input</string>
+ <!-- Bluetooth settings. Connection options screen. The summary for the Hearing Aid checkbox preference that describes how checking it will set the Hearing Aid profile as preferred. -->
+ <string name="bluetooth_hearing_aid_profile_summary_use_for">Use for Hearing Aid</string>
<!-- Button text for accepting an incoming pairing request. [CHAR LIMIT=20] -->
<string name="bluetooth_pairing_accept">Pair</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 1f67dfb568a6..9947dec14d48 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -1,6 +1,7 @@
package com.android.settingslib;
import android.annotation.ColorInt;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
@@ -17,10 +18,13 @@ import android.graphics.drawable.Drawable;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.os.BatteryManager;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.print.PrintManager;
import android.provider.Settings;
+
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.UserIcons;
import com.android.settingslib.drawable.UserIconDrawable;
import com.android.settingslib.wrapper.LocationManagerWrapper;
@@ -30,6 +34,9 @@ public class Utils {
private static final String CURRENT_MODE_KEY = "CURRENT_MODE";
private static final String NEW_MODE_KEY = "NEW_MODE";
+ @VisibleForTesting
+ static final String STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY =
+ "ro.storage_manager.show_opt_in";
private static Signature[] sSystemSignature;
private static String sPermissionControllerPackageName;
@@ -37,11 +44,11 @@ public class Utils {
private static String sSharedSystemSharedLibPackageName;
static final int[] WIFI_PIE = {
- com.android.internal.R.drawable.ic_wifi_signal_0,
- com.android.internal.R.drawable.ic_wifi_signal_1,
- com.android.internal.R.drawable.ic_wifi_signal_2,
- com.android.internal.R.drawable.ic_wifi_signal_3,
- com.android.internal.R.drawable.ic_wifi_signal_4
+ com.android.internal.R.drawable.ic_wifi_signal_0,
+ com.android.internal.R.drawable.ic_wifi_signal_1,
+ com.android.internal.R.drawable.ic_wifi_signal_2,
+ com.android.internal.R.drawable.ic_wifi_signal_3,
+ com.android.internal.R.drawable.ic_wifi_signal_4
};
public static void updateLocationEnabled(Context context, boolean enabled, int userId,
@@ -262,7 +269,7 @@ public class Utils {
*/
public static boolean isSystemPackage(Resources resources, PackageManager pm, PackageInfo pkg) {
if (sSystemSignature == null) {
- sSystemSignature = new Signature[]{ getSystemSignature(pm) };
+ sSystemSignature = new Signature[]{getSystemSignature(pm)};
}
if (sPermissionControllerPackageName == null) {
sPermissionControllerPackageName = pm.getPermissionControllerPackageName();
@@ -274,7 +281,7 @@ public class Utils {
sSharedSystemSharedLibPackageName = pm.getSharedSystemSharedLibraryPackageName();
}
return (sSystemSignature[0] != null
- && sSystemSignature[0].equals(getFirstSignature(pkg)))
+ && sSystemSignature[0].equals(getFirstSignature(pkg)))
|| pkg.packageName.equals(sPermissionControllerPackageName)
|| pkg.packageName.equals(sServicesSystemSharedLibPackageName)
|| pkg.packageName.equals(sSharedSystemSharedLibPackageName)
@@ -312,7 +319,6 @@ public class Utils {
* Returns the Wifi icon resource for a given RSSI level.
*
* @param level The number of bars to show (0-4)
- *
* @throws IllegalArgumentException if an invalid RSSI level is given.
*/
public static int getWifiIconResource(int level) {
@@ -342,4 +348,19 @@ public class Utils {
return !context.getSystemService(ConnectivityManager.class)
.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
}
+
+ /** Returns if the automatic storage management feature is turned on or not. **/
+ public static boolean isStorageManagerEnabled(Context context) {
+ boolean isDefaultOn;
+ try {
+ // Turn off by default if the opt-in was shown.
+ isDefaultOn = !SystemProperties.getBoolean(STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY, true);
+ } catch (Resources.NotFoundException e) {
+ isDefaultOn = false;
+ }
+ return Settings.Secure.getInt(context.getContentResolver(),
+ Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED,
+ isDefaultOn ? 1 : 0)
+ != 0;
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
new file mode 100644
index 000000000000..8f9e4635bb4b
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -0,0 +1,235 @@
+/*
+ * 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.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothCodecConfig;
+import android.bluetooth.BluetoothCodecStatus;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class HearingAidProfile implements LocalBluetoothProfile {
+ private static final String TAG = "HearingAidProfile";
+ private static boolean V = true;
+
+ private Context mContext;
+
+ private BluetoothHearingAid mService;
+ private boolean mIsProfileReady;
+
+ private final LocalBluetoothAdapter mLocalAdapter;
+ private final CachedBluetoothDeviceManager mDeviceManager;
+
+ static final String NAME = "HearingAid";
+ private final LocalBluetoothProfileManager mProfileManager;
+
+ // Order of this profile in device profiles list
+ private static final int ORDINAL = 1;
+
+ // These callbacks run on the main thread.
+ private final class HearingAidServiceListener
+ implements BluetoothProfile.ServiceListener {
+
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (V) Log.d(TAG,"Bluetooth service connected");
+ mService = (BluetoothHearingAid) proxy;
+ // We just bound to the service, so refresh the UI for any connected HearingAid devices.
+ List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+ while (!deviceList.isEmpty()) {
+ BluetoothDevice nextDevice = deviceList.remove(0);
+ CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+ // we may add a new device here, but generally this should not happen
+ if (device == null) {
+ Log.w(TAG, "HearingAidProfile found new device: " + nextDevice);
+ device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
+ }
+ device.onProfileStateChanged(HearingAidProfile.this, BluetoothProfile.STATE_CONNECTED);
+ device.refresh();
+ }
+ mIsProfileReady=true;
+ }
+
+ public void onServiceDisconnected(int profile) {
+ if (V) Log.d(TAG,"Bluetooth service disconnected");
+ mIsProfileReady=false;
+ }
+ }
+
+ public boolean isProfileReady() {
+ return mIsProfileReady;
+ }
+
+ HearingAidProfile(Context context, LocalBluetoothAdapter adapter,
+ CachedBluetoothDeviceManager deviceManager,
+ LocalBluetoothProfileManager profileManager) {
+ mContext = context;
+ mLocalAdapter = adapter;
+ mDeviceManager = deviceManager;
+ mProfileManager = profileManager;
+ mLocalAdapter.getProfileProxy(context, new HearingAidServiceListener(),
+ BluetoothProfile.HEARING_AID);
+ }
+
+ public boolean isConnectable() {
+ return true;
+ }
+
+ public boolean isAutoConnectable() {
+ return true;
+ }
+
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (mService == null) return new ArrayList<BluetoothDevice>(0);
+ return mService.getDevicesMatchingConnectionStates(
+ new int[] {BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTING});
+ }
+
+ public boolean connect(BluetoothDevice device) {
+ if (mService == null) return false;
+ return mService.connect(device);
+ }
+
+ public boolean disconnect(BluetoothDevice device) {
+ if (mService == null) return false;
+ // Downgrade priority as user is disconnecting the hearing aid.
+ if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){
+ mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ }
+ return mService.disconnect(device);
+ }
+
+ public int getConnectionStatus(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ return mService.getConnectionState(device);
+ }
+
+ public boolean isPreferred(BluetoothDevice device) {
+ if (mService == null) return false;
+ return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+ }
+
+ public int getPreferred(BluetoothDevice device) {
+ if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+ return mService.getPriority(device);
+ }
+
+ public void setPreferred(BluetoothDevice device, boolean preferred) {
+ if (mService == null) return;
+ if (preferred) {
+ if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ }
+ } else {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+ }
+ }
+
+ public int getVolume() {
+ if (mService == null) {
+ return 0;
+ }
+ return mService.getVolume();
+ }
+
+ public void setVolume(int volume) {
+ if (mService == null) {
+ return;
+ }
+ mService.setVolume(volume);
+ }
+
+ public long getHiSyncId(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothHearingAid.HI_SYNC_ID_INVALID;
+ }
+ return mService.getHiSyncId(device);
+ }
+
+ public int getDeviceSide(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothHearingAid.SIDE_LEFT;
+ }
+ return mService.getDeviceSide(device);
+ }
+
+ public int getDeviceMode(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothHearingAid.MODE_MONAURAL;
+ }
+ return mService.getDeviceMode(device);
+ }
+
+ public String toString() {
+ return NAME;
+ }
+
+ public int getOrdinal() {
+ return ORDINAL;
+ }
+
+ public int getNameResource(BluetoothDevice device) {
+ return R.string.bluetooth_profile_hearing_aid;
+ }
+
+ public int getSummaryResourceForDevice(BluetoothDevice device) {
+ int state = getConnectionStatus(device);
+ switch (state) {
+ case BluetoothProfile.STATE_DISCONNECTED:
+ return R.string.bluetooth_hearing_aid_profile_summary_use_for;
+
+ case BluetoothProfile.STATE_CONNECTED:
+ return R.string.bluetooth_hearing_aid_profile_summary_connected;
+
+ default:
+ return Utils.getConnectionStateSummary(state);
+ }
+ }
+
+ public int getDrawableResource(BluetoothClass btClass) {
+ return R.drawable.ic_bt_hearing_aid;
+ }
+
+ protected void finalize() {
+ if (V) Log.d(TAG, "finalize()");
+ if (mService != null) {
+ try {
+ BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HEARING_AID,
+ mService);
+ mService = null;
+ }catch (Throwable t) {
+ Log.w(TAG, "Error cleaning up Hearing Aid proxy", t);
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 991d9221c796..34a099cb7ea0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -21,6 +21,7 @@ import android.bluetooth.BluetoothA2dpSink;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHeadsetClient;
+import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothHidHost;
import android.bluetooth.BluetoothMap;
import android.bluetooth.BluetoothMapClient;
@@ -91,6 +92,7 @@ public class LocalBluetoothProfileManager {
private final PbapServerProfile mPbapProfile;
private final boolean mUsePbapPce;
private final boolean mUseMapClient;
+ private HearingAidProfile mHearingAidProfile;
/**
* Mapping from profile name, e.g. "HEADSET" to profile object.
@@ -143,10 +145,14 @@ public class LocalBluetoothProfileManager {
//Create PBAP server profile
if(DEBUG) Log.d(TAG, "Adding local PBAP profile");
+
mPbapProfile = new PbapServerProfile(context);
addProfile(mPbapProfile, PbapServerProfile.NAME,
BluetoothPbap.ACTION_CONNECTION_STATE_CHANGED);
+ mHearingAidProfile = new HearingAidProfile(mContext, mLocalAdapter, mDeviceManager, this);
+ addProfile(mHearingAidProfile, HearingAidProfile.NAME,
+ BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
if (DEBUG) Log.d(TAG, "LocalBluetoothProfileManager construction complete");
}
@@ -254,6 +260,18 @@ public class LocalBluetoothProfileManager {
"Warning: PBAP Client profile was previously added but the UUID is now missing.");
}
+ //Hearing Aid Client
+ if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid)) {
+ if (mHearingAidProfile == null) {
+ if(DEBUG) Log.d(TAG, "Adding local Hearing Aid profile");
+ mHearingAidProfile = new HearingAidProfile(mContext, mLocalAdapter, mDeviceManager, this);
+ addProfile(mHearingAidProfile, HearingAidProfile.NAME,
+ BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
+ }
+ } else if (mHearingAidProfile != null) {
+ Log.w(TAG, "Warning: Hearing Aid profile was previously added but the UUID is now missing.");
+ }
+
mEventManager.registerProfileIntentReceiver();
// There is no local SDP record for HID and Settings app doesn't control PBAP Server.
@@ -416,6 +434,10 @@ public class LocalBluetoothProfileManager {
return mMapClientProfile;
}
+ public HearingAidProfile getHearingAidProfile() {
+ return mHearingAidProfile;
+ }
+
/**
* Fill in a list of LocalBluetoothProfile objects that are supported by
* the local device and the remote device.
@@ -515,6 +537,12 @@ public class LocalBluetoothProfileManager {
removedProfiles.remove(mPbapClientProfile);
}
+ if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid) &&
+ mHearingAidProfile != null) {
+ profiles.add(mHearingAidProfile);
+ removedProfiles.remove(mHearingAidProfile);
+ }
+
if (DEBUG) {
Log.d(TAG,"New Profiles" + profiles.toString());
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
index 1a54d6a3396b..b98f27ea62d0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
@@ -76,6 +76,8 @@ public class EnableZenModeDialog {
protected Uri mForeverId;
private int mBucketIndex = -1;
+ @VisibleForTesting
+ protected NotificationManager mNotificationManager;
private AlarmManager mAlarmManager;
private int mUserId;
private boolean mAttached;
@@ -98,7 +100,7 @@ public class EnableZenModeDialog {
}
public Dialog createDialog() {
- NotificationManager noMan = (NotificationManager) mContext.
+ mNotificationManager = (NotificationManager) mContext.
getSystemService(Context.NOTIFICATION_SERVICE);
mForeverId = Condition.newId(mContext).appendPath("forever").build();
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
@@ -131,7 +133,8 @@ public class EnableZenModeDialog {
Slog.d(TAG, "Invalid manual condition: " + tag.condition);
}
// always triggers priority-only dnd with chosen condition
- noMan.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ mNotificationManager.setZenMode(
+ Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
getRealConditionId(tag.condition), TAG);
}
});
@@ -465,7 +468,16 @@ public class EnableZenModeDialog {
mZenAlarmWarning.setVisibility(warningText == null ? View.GONE : View.VISIBLE);
}
- private String computeAlarmWarningText(Condition condition) {
+ @VisibleForTesting
+ protected String computeAlarmWarningText(Condition condition) {
+ boolean allowAlarms = (mNotificationManager.getNotificationPolicy().priorityCategories
+ & NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS) != 0;
+
+ // don't show alarm warning if alarms are allowed to bypass dnd
+ if (allowAlarms) {
+ return null;
+ }
+
final long now = System.currentTimeMillis();
final long nextAlarm = getNextAlarm();
if (nextAlarm < now) {
@@ -483,14 +495,19 @@ public class EnableZenModeDialog {
if (warningRes == 0) {
return null;
}
+
+ return mContext.getResources().getString(warningRes, getTime(nextAlarm, now));
+ }
+
+ @VisibleForTesting
+ protected String getTime(long nextAlarm, long now) {
final boolean soon = (nextAlarm - now) < 24 * 60 * 60 * 1000;
final boolean is24 = DateFormat.is24HourFormat(mContext, ActivityManager.getCurrentUser());
final String skeleton = soon ? (is24 ? "Hm" : "hma") : (is24 ? "EEEHm" : "EEEhma");
final String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
final CharSequence formattedTime = DateFormat.format(pattern, nextAlarm);
final int templateRes = soon ? R.string.alarm_template : R.string.alarm_template_far;
- final String template = mContext.getResources().getString(templateRes, formattedTime);
- return mContext.getResources().getString(warningRes, template);
+ return mContext.getResources().getString(templateRes, formattedTime);
}
// used as the view tag on condition rows
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index f69944006a87..c5c116982b42 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -17,6 +17,7 @@
package com.android.settingslib.wifi;
import android.annotation.IntDef;
+import android.annotation.MainThread;
import android.annotation.Nullable;
import android.app.AppGlobals;
import android.content.Context;
@@ -42,6 +43,8 @@ import android.net.wifi.WifiManager;
import android.net.wifi.WifiNetworkScoreCache;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -57,6 +60,7 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.R;
+import com.android.settingslib.utils.ThreadUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -68,7 +72,14 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
-
+/**
+ * Represents a selectable Wifi Network for use in various wifi selection menus backed by
+ * {@link WifiTracker}.
+ *
+ * <p>An AccessPoint, which would be more fittingly named "WifiNetwork", is an aggregation of
+ * {@link ScanResult ScanResults} along with pertinent metadata (e.g. current connection info,
+ * network scores) required to successfully render the network to the user.
+ */
public class AccessPoint implements Comparable<AccessPoint> {
static final String TAG = "SettingsLib.AccessPoint";
@@ -288,11 +299,6 @@ public class AccessPoint implements Comparable<AccessPoint> {
mId = sLastId.incrementAndGet();
}
- AccessPoint(Context context, AccessPoint other) {
- mContext = context;
- copyFrom(other);
- }
-
AccessPoint(Context context, Collection<ScanResult> results) {
mContext = context;
@@ -346,33 +352,6 @@ public class AccessPoint implements Comparable<AccessPoint> {
}
/**
- * Copy accesspoint information. NOTE: We do not copy tag information because that is never
- * set on the internal copy.
- */
- void copyFrom(AccessPoint that) {
- this.ssid = that.ssid;
- this.bssid = that.bssid;
- this.security = that.security;
- this.mKey = that.mKey;
- this.networkId = that.networkId;
- this.pskType = that.pskType;
- this.mConfig = that.mConfig; //TODO: Watch out, this object is mutated.
- this.mRssi = that.mRssi;
- this.mInfo = that.mInfo;
- this.mNetworkInfo = that.mNetworkInfo;
- this.mScanResults.clear();
- this.mScanResults.addAll(that.mScanResults);
- this.mScoredNetworkCache.clear();
- this.mScoredNetworkCache.putAll(that.mScoredNetworkCache);
- this.mId = that.mId;
- this.mSpeed = that.mSpeed;
- this.mIsScoredNetworkMetered = that.mIsScoredNetworkMetered;
- this.mIsCarrierAp = that.mIsCarrierAp;
- this.mCarrierApEapType = that.mCarrierApEapType;
- this.mCarrierName = that.mCarrierName;
- }
-
- /**
* Returns a negative integer, zero, or a positive integer if this AccessPoint is less than,
* equal to, or greater than the other AccessPoint.
*
@@ -467,7 +446,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
}
builder.append(",metered=").append(isMetered());
- if (WifiTracker.sVerboseLogging) {
+ if (isVerboseLoggingEnabled()) {
builder.append(",rssi=").append(mRssi);
builder.append(",scan cache size=").append(mScanResults.size());
}
@@ -546,7 +525,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
mSpeed = generateAverageSpeedForSsid();
boolean changed = oldSpeed != mSpeed;
- if(WifiTracker.sVerboseLogging && changed) {
+ if(isVerboseLoggingEnabled() && changed) {
Log.i(TAG, String.format("%s: Set speed to %d", ssid, mSpeed));
}
return changed;
@@ -577,7 +556,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
}
}
int speed = count == 0 ? Speed.NONE : totalSpeed / count;
- if (WifiTracker.sVerboseLogging) {
+ if (isVerboseLoggingEnabled()) {
Log.i(TAG, String.format("%s generated fallback speed is: %d", getSsidStr(), speed));
}
return roundToClosestSpeedEnum(speed);
@@ -913,7 +892,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
}
}
- if (WifiTracker.sVerboseLogging) {
+ if (isVerboseLoggingEnabled()) {
summary.append(WifiUtils.buildLoggingSummary(this, config));
}
@@ -1069,15 +1048,20 @@ public class AccessPoint implements Comparable<AccessPoint> {
if (newLevel > 0 && newLevel != oldLevel) {
// Only update labels on visible rssi changes
updateSpeed();
- if (mAccessPointListener != null) {
- mAccessPointListener.onLevelChanged(this);
- }
- }
+ ThreadUtils.postOnMainThread(() -> {
+ if (mAccessPointListener != null) {
+ mAccessPointListener.onLevelChanged(this);
+ }
+ });
- if (mAccessPointListener != null) {
- mAccessPointListener.onAccessPointChanged(this);
}
+ ThreadUtils.postOnMainThread(() -> {
+ if (mAccessPointListener != null) {
+ mAccessPointListener.onAccessPointChanged(this);
+ }
+ });
+
if (!scanResults.isEmpty()) {
ScanResult result = scanResults.iterator().next();
@@ -1123,10 +1107,18 @@ public class AccessPoint implements Comparable<AccessPoint> {
mNetworkInfo = null;
}
if (updated && mAccessPointListener != null) {
- mAccessPointListener.onAccessPointChanged(this);
+ ThreadUtils.postOnMainThread(() -> {
+ if (mAccessPointListener != null) {
+ mAccessPointListener.onAccessPointChanged(this);
+ }
+ });
if (oldLevel != getLevel() /* current level */) {
- mAccessPointListener.onLevelChanged(this);
+ ThreadUtils.postOnMainThread(() -> {
+ if (mAccessPointListener != null) {
+ mAccessPointListener.onLevelChanged(this);
+ }
+ });
}
}
@@ -1136,9 +1128,11 @@ public class AccessPoint implements Comparable<AccessPoint> {
void update(@Nullable WifiConfiguration config) {
mConfig = config;
networkId = config != null ? config.networkId : WifiConfiguration.INVALID_NETWORK_ID;
- if (mAccessPointListener != null) {
- mAccessPointListener.onAccessPointChanged(this);
- }
+ ThreadUtils.postOnMainThread(() -> {
+ if (mAccessPointListener != null) {
+ mAccessPointListener.onAccessPointChanged(this);
+ }
+ });
}
@VisibleForTesting
@@ -1333,8 +1327,44 @@ public class AccessPoint implements Comparable<AccessPoint> {
return string;
}
+ /**
+ * Callbacks relaying changes to the AccessPoint representation.
+ *
+ * <p>All methods are invoked on the Main Thread.
+ */
public interface AccessPointListener {
- void onAccessPointChanged(AccessPoint accessPoint);
- void onLevelChanged(AccessPoint accessPoint);
+ /**
+ * Indicates a change to the externally visible state of the AccessPoint trigger by an
+ * update of ScanResults, saved configuration state, connection state, or score
+ * (labels/metered) state.
+ *
+ * <p>Clients should refresh their view of the AccessPoint to match the updated state when
+ * this is invoked. Overall this method is extraneous if clients are listening to
+ * {@link WifiTracker.WifiListener#onAccessPointsChanged()} callbacks.
+ *
+ * <p>Examples of changes include signal strength, connection state, speed label, and
+ * generally anything that would impact the summary string.
+ *
+ * @param accessPoint The accessPoint object the listener was registered on which has
+ * changed
+ */
+ @MainThread void onAccessPointChanged(AccessPoint accessPoint);
+
+ /**
+ * Indicates the "wifi pie signal level" has changed, retrieved via calls to
+ * {@link AccessPoint#getLevel()}.
+ *
+ * <p>This call is a subset of {@link #onAccessPointChanged(AccessPoint)} , hence is also
+ * extraneous if the client is already reacting to that or the
+ * {@link WifiTracker.WifiListener#onAccessPointsChanged()} callbacks.
+ *
+ * @param accessPoint The accessPoint object the listener was registered on whose level has
+ * changed
+ */
+ @MainThread void onLevelChanged(AccessPoint accessPoint);
+ }
+
+ private static boolean isVerboseLoggingEnabled() {
+ return WifiTracker.sVerboseLogging || Log.isLoggable(TAG, Log.VERBOSE);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index fac585e06306..ae544dd6dbe8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -15,6 +15,7 @@
*/
package com.android.settingslib.wifi;
+import android.annotation.AnyThread;
import android.annotation.MainThread;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -48,8 +49,6 @@ import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
import android.widget.Toast;
import com.android.settingslib.R;
@@ -58,6 +57,7 @@ import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnDestroy;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.android.settingslib.utils.ThreadUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -88,8 +88,17 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
return Log.isLoggable(TAG, Log.DEBUG);
}
- /** verbose logging flag. this flag is set thru developer debugging options
- * and used so as to assist with in-the-field WiFi connectivity debugging */
+ private static boolean isVerboseLoggingEnabled() {
+ return WifiTracker.sVerboseLogging || Log.isLoggable(TAG, Log.VERBOSE);
+ }
+
+ /**
+ * Verbose logging flag set thru developer debugging options and used so as to assist with
+ * in-the-field WiFi connectivity debugging.
+ *
+ * <p>{@link #isVerboseLoggingEnabled()} should be read rather than referencing this value
+ * directly, to ensure adb TAG level verbose settings are respected.
+ */
public static boolean sVerboseLogging;
// TODO: Allow control of this?
@@ -104,7 +113,6 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
private final NetworkRequest mNetworkRequest;
private final AtomicBoolean mConnected = new AtomicBoolean(false);
private final WifiListener mListener;
- @VisibleForTesting MainHandler mMainHandler;
@VisibleForTesting WorkHandler mWorkHandler;
private HandlerThread mWorkThread;
@@ -113,35 +121,17 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
@GuardedBy("mLock")
private boolean mRegistered;
- /**
- * The externally visible access point list.
- *
- * Updated using main handler. Clone of this collection is returned from
- * {@link #getAccessPoints()}
- */
- private final List<AccessPoint> mAccessPoints = new ArrayList<>();
-
- /**
- * The internal list of access points, synchronized on itself.
- *
- * Never exposed outside this class.
- */
+ /** The list of AccessPoints, aggregated visible ScanResults with metadata. */
@GuardedBy("mLock")
private final List<AccessPoint> mInternalAccessPoints = new ArrayList<>();
/**
* Synchronization lock for managing concurrency between main and worker threads.
*
- * <p>This lock should be held for all background work.
- * TODO(b/37674366): Remove the worker thread so synchronization is no longer necessary.
+ * <p>This lock should be held for all modifications to {@link #mInternalAccessPoints}.
*/
private final Object mLock = new Object();
- //visible to both worker and main thread.
- @GuardedBy("mLock")
- private final AccessPointListenerAdapter mAccessPointListenerAdapter
- = new AccessPointListenerAdapter();
-
private final HashMap<String, Integer> mSeenBssids = new HashMap<>();
// TODO(sghuman): Change this to be keyed on AccessPoint.getKey
@@ -161,6 +151,12 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
@VisibleForTesting
Scanner mScanner;
+ /**
+ * Tracks whether fresh scan results have been received since scanning start.
+ *
+ * <p>If this variable is false, we will not evict the scan result cache or invoke callbacks
+ * so that we do not update the UI with stale data / clear out existing UI elements prematurely.
+ */
@GuardedBy("mLock")
private boolean mStaleScanResults = true;
@@ -209,12 +205,11 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
NetworkScoreManager networkScoreManager,
IntentFilter filter) {
mContext = context;
- mMainHandler = new MainHandler(Looper.getMainLooper());
mWifiManager = wifiManager;
mListener = new WifiListenerWrapper(wifiListener);
mConnectivityManager = connectivityManager;
- // check if verbose logging has been turned on or off
+ // check if verbose logging developer option has been turned on or off
sVerboseLogging = (mWifiManager.getVerboseLoggingLevel() > 0);
mFilter = filter;
@@ -226,6 +221,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
mNetworkScoreManager = networkScoreManager;
+ // TODO(sghuman): Remove this and create less hacky solution for testing
final HandlerThread workThread = new HandlerThread(TAG
+ "{" + Integer.toHexString(System.identityHashCode(this)) + "}",
Process.THREAD_PRIORITY_BACKGROUND);
@@ -238,6 +234,8 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
* @param workThread substitute Handler thread, for testing purposes only
*/
@VisibleForTesting
+ // TODO(sghuman): Remove this method, this needs to happen in a factory method and be passed in
+ // during construction
void setWorkThread(HandlerThread workThread) {
mWorkThread = workThread;
mWorkHandler = new WorkHandler(workThread.getLooper());
@@ -270,32 +268,29 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
mLastNetworkInfo = mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork());
final List<ScanResult> newScanResults = mWifiManager.getScanResults();
- if (sVerboseLogging) {
+ if (isVerboseLoggingEnabled()) {
Log.i(TAG, "Fetched scan results: " + newScanResults);
}
List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
mInternalAccessPoints.clear();
updateAccessPointsLocked(newScanResults, configs);
-
- // Synchronously copy access points
- mMainHandler.removeMessages(MainHandler.MSG_ACCESS_POINT_CHANGED);
- mMainHandler.handleMessage(
- Message.obtain(mMainHandler, MainHandler.MSG_ACCESS_POINT_CHANGED));
- if (sVerboseLogging) {
- Log.i(TAG, "force update - external access point list:\n" + mAccessPoints);
- }
}
}
/**
* Temporarily stop scanning for wifi networks.
+ *
+ * <p>Sets {@link #mStaleScanResults} to true.
*/
- public void pauseScanning() {
+ private void pauseScanning() {
if (mScanner != null) {
mScanner.pause();
mScanner = null;
}
+ synchronized (mLock) {
+ mStaleScanResults = true;
+ }
}
/**
@@ -387,11 +382,9 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
mRegistered = false;
}
unregisterScoreCache();
- pauseScanning();
+ pauseScanning(); // and set mStaleScanResults
mWorkHandler.removePendingMessages();
- mMainHandler.removePendingMessages();
- mStaleScanResults = true;
}
}
@@ -409,12 +402,19 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
}
/**
- * Gets the current list of access points. Should be called from main thread, otherwise
- * expect inconsistencies
+ * Gets the current list of access points.
+ *
+ * <p>This method is can be called on an abitrary thread by clients, but is normally called on
+ * the UI Thread by the rendering App.
*/
- @MainThread
+ @AnyThread
public List<AccessPoint> getAccessPoints() {
- return new ArrayList<>(mAccessPoints);
+ // TODO(sghuman): Investigate how to eliminate or reduce the need for locking now that we
+ // have transitioned to a single worker thread model.
+
+ synchronized (mLock) {
+ return new ArrayList<>(mInternalAccessPoints);
+ }
}
public WifiManager getManager() {
@@ -447,6 +447,8 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
}
private void handleResume() {
+ // TODO(sghuman): Investigate removing this and replacing it with a cache eviction call
+ // instead.
mScanResultCache.clear();
mSeenBssids.clear();
}
@@ -509,7 +511,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
private void updateAccessPoints() {
List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
final List<ScanResult> newScanResults = mWifiManager.getScanResults();
- if (sVerboseLogging) {
+ if (isVerboseLoggingEnabled()) {
Log.i(TAG, "Fetched scan results: " + newScanResults);
}
@@ -524,11 +526,15 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
* Update the internal list of access points.
*
* <p>Do not call directly (except for forceUpdate), use {@link #updateAccessPoints()} which
- * respects {@link #mStaleScanResults}.
+ * acquires the lock first.
*/
@GuardedBy("mLock")
private void updateAccessPointsLocked(final List<ScanResult> newScanResults,
List<WifiConfiguration> configs) {
+ // TODO(sghuman): Reduce the synchronization time by only holding the lock when
+ // modifying lists exposed to operations on the MainThread (getAccessPoints, stopTracking,
+ // startTracking, etc).
+
WifiConfiguration connectionConfig = null;
if (mLastInfo != null) {
connectionConfig = getWifiConfigurationForNetworkId(
@@ -634,7 +640,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
mInternalAccessPoints.clear();
mInternalAccessPoints.addAll(accessPoints);
- mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED);
+ conditionallyNotifyListeners();
}
@VisibleForTesting
@@ -650,7 +656,6 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
}
}
final AccessPoint accessPoint = new AccessPoint(mContext, scanResults);
- accessPoint.setListener(mAccessPointListenerAdapter);
return accessPoint;
}
@@ -661,16 +666,17 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
if (cache.get(i).matches(config)) {
AccessPoint ret = cache.remove(i);
ret.loadConfig(config);
+
return ret;
}
}
final AccessPoint accessPoint = new AccessPoint(mContext, config);
- accessPoint.setListener(mAccessPointListenerAdapter);
return accessPoint;
}
private void updateNetworkInfo(NetworkInfo networkInfo) {
- /* sticky broadcasts can call this when wifi is disabled */
+
+ /* Sticky broadcasts can call this when wifi is disabled */
if (!mWifiManager.isWifiEnabled()) {
clearAccessPointsAndConditionallyUpdate();
return;
@@ -681,6 +687,10 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
if (DBG()) {
Log.d(TAG, "mLastNetworkInfo set: " + mLastNetworkInfo);
}
+
+ if(networkInfo.isConnected() != mConnected.getAndSet(networkInfo.isConnected())) {
+ mListener.onConnectedChanged();
+ }
}
WifiConfiguration connectionConfig = null;
@@ -711,18 +721,25 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
}
}
- if (reorder) Collections.sort(mInternalAccessPoints);
- if (updated) mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED);
+ if (reorder) {
+ Collections.sort(mInternalAccessPoints);
+ }
+ if (updated) {
+ conditionallyNotifyListeners();
+ }
}
}
+ /**
+ * Clears the access point list and conditionally invokes
+ * {@link WifiListener#onAccessPointsChanged()} if required (i.e. the list was not already
+ * empty).
+ */
private void clearAccessPointsAndConditionallyUpdate() {
synchronized (mLock) {
if (!mInternalAccessPoints.isEmpty()) {
mInternalAccessPoints.clear();
- if (!mMainHandler.hasMessages(MainHandler.MSG_ACCESS_POINT_CHANGED)) {
- mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED);
- }
+ mListener.onAccessPointsChanged();
}
}
}
@@ -745,27 +762,26 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
}
if (updated) {
Collections.sort(mInternalAccessPoints);
- mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED);
+ conditionallyNotifyListeners();
}
}
}
- private void updateWifiState(int state) {
- mWorkHandler.obtainMessage(WorkHandler.MSG_UPDATE_WIFI_STATE, state, 0).sendToTarget();
- if (!mWifiManager.isWifiEnabled()) {
- clearAccessPointsAndConditionallyUpdate();
- }
- }
-
@VisibleForTesting
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ // No work should be performed in this Receiver, instead all operations should be passed
+ // off to the WorkHandler to avoid concurrent modification exceptions.
+
String action = intent.getAction();
if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
- updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
- WifiManager.WIFI_STATE_UNKNOWN));
+ mWorkHandler.obtainMessage(
+ WorkHandler.MSG_UPDATE_WIFI_STATE,
+ intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+ WifiManager.WIFI_STATE_UNKNOWN),
+ 0).sendToTarget();
} else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
mWorkHandler
.obtainMessage(
@@ -778,12 +794,6 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
mWorkHandler.sendEmptyMessage(WorkHandler.MSG_UPDATE_ACCESS_POINTS);
} else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
-
- if(mConnected.get() != info.isConnected()) {
- mConnected.set(info.isConnected());
- mMainHandler.sendEmptyMessage(MainHandler.MSG_CONNECTED_CHANGED);
- }
-
mWorkHandler.obtainMessage(WorkHandler.MSG_UPDATE_NETWORK_INFO, info)
.sendToTarget();
mWorkHandler.sendEmptyMessage(WorkHandler.MSG_UPDATE_ACCESS_POINTS);
@@ -808,68 +818,8 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
}
@VisibleForTesting
- final class MainHandler extends Handler {
- @VisibleForTesting static final int MSG_CONNECTED_CHANGED = 0;
- @VisibleForTesting static final int MSG_WIFI_STATE_CHANGED = 1;
- @VisibleForTesting static final int MSG_ACCESS_POINT_CHANGED = 2;
- private static final int MSG_RESUME_SCANNING = 3;
- private static final int MSG_PAUSE_SCANNING = 4;
-
- public MainHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (mListener == null) {
- return;
- }
- switch (msg.what) {
- case MSG_CONNECTED_CHANGED:
- mListener.onConnectedChanged();
- break;
- case MSG_WIFI_STATE_CHANGED:
- mListener.onWifiStateChanged(msg.arg1);
- break;
- case MSG_ACCESS_POINT_CHANGED:
- // Only notify listeners of changes if we have fresh scan results, otherwise the
- // UI will be updated with stale results. We want to copy the APs regardless,
- // for instances where forceUpdate was invoked by the caller.
- if (mStaleScanResults) {
- copyAndNotifyListeners(false /*notifyListeners*/);
- } else {
- copyAndNotifyListeners(true /*notifyListeners*/);
- mListener.onAccessPointsChanged();
- }
- break;
- case MSG_RESUME_SCANNING:
- if (mScanner != null) {
- mScanner.resume();
- }
- break;
- case MSG_PAUSE_SCANNING:
- if (mScanner != null) {
- mScanner.pause();
- }
- synchronized (mLock) {
- mStaleScanResults = true;
- }
- break;
- }
- }
-
- void removePendingMessages() {
- removeMessages(MSG_ACCESS_POINT_CHANGED);
- removeMessages(MSG_CONNECTED_CHANGED);
- removeMessages(MSG_WIFI_STATE_CHANGED);
- removeMessages(MSG_PAUSE_SCANNING);
- removeMessages(MSG_RESUME_SCANNING);
- }
- }
-
- @VisibleForTesting
final class WorkHandler extends Handler {
- private static final int MSG_UPDATE_ACCESS_POINTS = 0;
+ @VisibleForTesting static final int MSG_UPDATE_ACCESS_POINTS = 0;
private static final int MSG_UPDATE_NETWORK_INFO = 1;
private static final int MSG_RESUME = 2;
private static final int MSG_UPDATE_WIFI_STATE = 3;
@@ -882,6 +832,8 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
@Override
public void handleMessage(Message msg) {
+ // TODO(sghuman): Clean up synchronization to only be used when modifying collections
+ // exposed to the MainThread (through onStart, onStop, forceUpdate).
synchronized (mLock) {
processMessage(msg);
}
@@ -911,6 +863,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
mScanner.resume();
}
} else {
+ clearAccessPointsAndConditionallyUpdate();
mLastInfo = null;
mLastNetworkInfo = null;
if (mScanner != null) {
@@ -920,8 +873,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
mStaleScanResults = true;
}
}
- mMainHandler.obtainMessage(MainHandler.MSG_WIFI_STATE_CHANGED, msg.arg1, 0)
- .sendToTarget();
+ mListener.onWifiStateChanged(msg.arg1);
break;
}
}
@@ -1010,16 +962,26 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
@Override
public void onWifiStateChanged(int state) {
+ if (isVerboseLoggingEnabled()) {
+ Log.i(TAG,
+ String.format("Invoking onWifiStateChanged callback with state %d", state));
+ }
mHandler.post(() -> mDelegatee.onWifiStateChanged(state));
}
@Override
public void onConnectedChanged() {
+ if (isVerboseLoggingEnabled()) {
+ Log.i(TAG, "Invoking onConnectedChanged callback");
+ }
mHandler.post(() -> mDelegatee.onConnectedChanged());
}
@Override
public void onAccessPointsChanged() {
+ if (isVerboseLoggingEnabled()) {
+ Log.i(TAG, "Invoking onAccessPointsChanged callback");
+ }
mHandler.post(() -> mDelegatee.onAccessPointsChanged());
}
}
@@ -1041,101 +1003,27 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
void onWifiStateChanged(int state);
/**
- * Called when the connection state of wifi has changed and isConnected
- * should be called to get the updated state.
+ * Called when the connection state of wifi has changed and
+ * {@link WifiTracker#isConnected()} should be called to get the updated state.
*/
void onConnectedChanged();
/**
* Called to indicate the list of AccessPoints has been updated and
- * getAccessPoints should be called to get the latest information.
+ * {@link WifiTracker#getAccessPoints()} should be called to get the updated list.
*/
void onAccessPointsChanged();
}
/**
- * Helps capture notifications that were generated during AccessPoint modification. Used later
- * on by {@link #copyAndNotifyListeners(boolean)} to send notifications.
+ * Invokes {@link WifiListenerWrapper#onAccessPointsChanged()} if {@link #mStaleScanResults}
+ * is false.
*/
- private static class AccessPointListenerAdapter implements AccessPoint.AccessPointListener {
- static final int AP_CHANGED = 1;
- static final int LEVEL_CHANGED = 2;
-
- final SparseIntArray mPendingNotifications = new SparseIntArray();
-
- @Override
- public void onAccessPointChanged(AccessPoint accessPoint) {
- int type = mPendingNotifications.get(accessPoint.mId);
- mPendingNotifications.put(accessPoint.mId, type | AP_CHANGED);
- }
-
- @Override
- public void onLevelChanged(AccessPoint accessPoint) {
- int type = mPendingNotifications.get(accessPoint.mId);
- mPendingNotifications.put(accessPoint.mId, type | LEVEL_CHANGED);
- }
- }
-
- /**
- * Responsible for copying access points from {@link #mInternalAccessPoints} and notifying
- * accesspoint listeners.
- *
- * @param notifyListeners if true, accesspoint listeners are notified, otherwise notifications
- * dropped.
- */
- @MainThread
- private void copyAndNotifyListeners(boolean notifyListeners) {
- // Need to watch out for memory allocations on main thread.
- SparseArray<AccessPoint> oldAccessPoints = new SparseArray<>();
- SparseIntArray notificationMap = null;
- List<AccessPoint> updatedAccessPoints = new ArrayList<>();
-
- for (AccessPoint accessPoint : mAccessPoints) {
- oldAccessPoints.put(accessPoint.mId, accessPoint);
- }
-
- synchronized (mLock) {
- if (DBG()) {
- Log.d(TAG, "Starting to copy AP items on the MainHandler. Internal APs: "
- + mInternalAccessPoints);
- }
-
- if (notifyListeners) {
- notificationMap = mAccessPointListenerAdapter.mPendingNotifications.clone();
- }
-
- mAccessPointListenerAdapter.mPendingNotifications.clear();
-
- for (AccessPoint internalAccessPoint : mInternalAccessPoints) {
- AccessPoint accessPoint = oldAccessPoints.get(internalAccessPoint.mId);
- if (accessPoint == null) {
- accessPoint = new AccessPoint(mContext, internalAccessPoint);
- } else {
- accessPoint.copyFrom(internalAccessPoint);
- }
- updatedAccessPoints.add(accessPoint);
- }
+ private void conditionallyNotifyListeners() {
+ if (mStaleScanResults) {
+ return;
}
- mAccessPoints.clear();
- mAccessPoints.addAll(updatedAccessPoints);
-
- if (notificationMap != null && notificationMap.size() > 0) {
- for (AccessPoint accessPoint : updatedAccessPoints) {
- int notificationType = notificationMap.get(accessPoint.mId);
- AccessPoint.AccessPointListener listener = accessPoint.mAccessPointListener;
- if (notificationType == 0 || listener == null) {
- continue;
- }
-
- if ((notificationType & AccessPointListenerAdapter.AP_CHANGED) != 0) {
- listener.onAccessPointChanged(accessPoint);
- }
-
- if ((notificationType & AccessPointListenerAdapter.LEVEL_CHANGED) != 0) {
- listener.onLevelChanged(accessPoint);
- }
- }
- }
+ ThreadUtils.postOnMainThread(() -> mListener.onAccessPointsChanged());
}
}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 144031108662..54c02a22e79f 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -113,38 +113,6 @@ public class AccessPointTest {
}
@Test
- public void testCopyAccessPoint_dataShouldMatch() {
- WifiConfiguration configuration = createWifiConfiguration();
- configuration.meteredHint = true;
-
- NetworkInfo networkInfo =
- new NetworkInfo(ConnectivityManager.TYPE_WIFI, 2, "WIFI", "WIFI_SUBTYPE");
- AccessPoint originalAccessPoint = new AccessPoint(mContext, configuration);
- WifiInfo wifiInfo = new WifiInfo();
- wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(configuration.SSID));
- wifiInfo.setBSSID(configuration.BSSID);
- originalAccessPoint.update(configuration, wifiInfo, networkInfo);
- AccessPoint copy = new AccessPoint(mContext, originalAccessPoint);
-
- assertThat(originalAccessPoint.getSsid().toString()).isEqualTo(copy.getSsid().toString());
- assertThat(originalAccessPoint.getBssid()).isEqualTo(copy.getBssid());
- assertThat(originalAccessPoint.getConfig()).isEqualTo(copy.getConfig());
- assertThat(originalAccessPoint.getSecurity()).isEqualTo(copy.getSecurity());
- assertThat(originalAccessPoint.isMetered()).isEqualTo(copy.isMetered());
- assertThat(originalAccessPoint.compareTo(copy) == 0).isTrue();
- }
-
- @Test
- public void testThatCopyAccessPoint_scanCacheShouldMatch() {
- AccessPoint original = createAccessPointWithScanResultCache();
- assertThat(original.getRssi()).isEqualTo(4);
- AccessPoint copy = new AccessPoint(mContext, createWifiConfiguration());
- assertThat(copy.getRssi()).isEqualTo(AccessPoint.UNREACHABLE_RSSI);
- copy.copyFrom(original);
- assertThat(original.getRssi()).isEqualTo(copy.getRssi());
- }
-
- @Test
public void testCompareTo_GivesActiveBeforeInactive() {
AccessPoint activeAp = new TestAccessPointBuilder(mContext).setActive(true).build();
AccessPoint inactiveAp = new TestAccessPointBuilder(mContext).setActive(false).build();
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 6be4936413b7..0c49bb66a40e 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
@@ -356,19 +356,14 @@ public class WifiTrackerTest {
private void waitForHandlersToProcessCurrentlyEnqueuedMessages(WifiTracker tracker)
throws InterruptedException {
+ // TODO(sghuman): This should no longer be necessary in a single work handler model
+
CountDownLatch workerLatch = new CountDownLatch(1);
tracker.mWorkHandler.post(() -> {
workerLatch.countDown();
});
assertTrue("Latch timed out while waiting for WorkerHandler",
workerLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
-
- CountDownLatch mainLatch = new CountDownLatch(1);
- tracker.mMainHandler.post(() -> {
- mainLatch.countDown();
- });
- assertTrue("Latch timed out while waiting for MainHandler",
- mainLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
}
private void switchToNetwork2(WifiTracker tracker) throws InterruptedException {
@@ -390,38 +385,6 @@ public class WifiTrackerTest {
}
@Test
- public void testAccessPointListenerSetWhenLookingUpUsingScanResults() {
- ScanResult scanResult = new ScanResult();
- scanResult.level = 123;
- scanResult.BSSID = "bssid-" + 111;
- scanResult.timestamp = SystemClock.elapsedRealtime() * 1000;
- scanResult.capabilities = "";
-
- WifiTracker tracker = new WifiTracker(
- InstrumentationRegistry.getTargetContext(), null, true, true);
-
- AccessPoint result = tracker.getCachedOrCreate(
- Collections.singletonList(scanResult), new ArrayList<AccessPoint>());
- assertTrue(result.mAccessPointListener != null);
- }
-
- @Test
- public void testAccessPointListenerSetWhenLookingUpUsingWifiConfiguration() {
- WifiConfiguration configuration = new WifiConfiguration();
- configuration.SSID = "test123";
- configuration.BSSID="bssid";
- configuration.networkId = 123;
- configuration.allowedKeyManagement = new BitSet();
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
-
- WifiTracker tracker = new WifiTracker(
- InstrumentationRegistry.getTargetContext(), null, true, true);
-
- AccessPoint result = tracker.getCachedOrCreate(configuration, new ArrayList<AccessPoint>());
- assertTrue(result.mAccessPointListener != null);
- }
-
- @Test
public void startAndStopTrackingShouldRegisterAndUnregisterScoreCache()
throws InterruptedException {
WifiTracker tracker = createMockedWifiTracker();
@@ -534,7 +497,6 @@ public class WifiTrackerTest {
waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
}
- @FlakyTest
@Test
public void scoreCacheUpdateScoresShouldChangeSortOrder() throws InterruptedException {
WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
@@ -634,9 +596,9 @@ public class WifiTrackerTest {
public void scoresShouldBeRequestedForNewScanResultOnly() throws InterruptedException {
// Scores can be requested together or serially depending on how the scan results are
// processed.
- mRequestScoresLatch = new CountDownLatch(2);
+ mRequestScoresLatch = new CountDownLatch(1);
WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
- mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+ assertTrue(mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
mRequestedKeys.clear();
String ssid = "ssid3";
@@ -770,7 +732,7 @@ public class WifiTrackerTest {
CountDownLatch ready = new CountDownLatch(1);
CountDownLatch latch = new CountDownLatch(1);
CountDownLatch lock = new CountDownLatch(1);
- tracker.mMainHandler.post(() -> {
+ tracker.mWorkHandler.post(() -> {
try {
ready.countDown();
lock.await();
@@ -781,12 +743,7 @@ public class WifiTrackerTest {
});
// Enqueue messages
- tracker.mMainHandler.sendEmptyMessage(
- WifiTracker.MainHandler.MSG_ACCESS_POINT_CHANGED);
- tracker.mMainHandler.sendEmptyMessage(
- WifiTracker.MainHandler.MSG_CONNECTED_CHANGED);
- tracker.mMainHandler.sendEmptyMessage(
- WifiTracker.MainHandler.MSG_WIFI_STATE_CHANGED);
+ tracker.mWorkHandler.sendEmptyMessage(WifiTracker.WorkHandler.MSG_UPDATE_ACCESS_POINTS);
try {
ready.await(); // Make sure we have entered the first message handler
@@ -800,12 +757,9 @@ public class WifiTrackerTest {
lock.countDown();
assertTrue("Latch timed out", latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
- assertThat(tracker.mMainHandler.hasMessages(
- WifiTracker.MainHandler.MSG_ACCESS_POINT_CHANGED)).isFalse();
- assertThat(tracker.mMainHandler.hasMessages(
- WifiTracker.MainHandler.MSG_CONNECTED_CHANGED)).isFalse();
- assertThat(tracker.mMainHandler.hasMessages(
- WifiTracker.MainHandler.MSG_WIFI_STATE_CHANGED)).isFalse();
+ assertThat(tracker.mWorkHandler.hasMessages(
+ WifiTracker.WorkHandler.MSG_UPDATE_ACCESS_POINTS)).isFalse();
+ waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
verifyNoMoreInteractions(mockWifiListener);
}
@@ -862,7 +816,7 @@ public class WifiTrackerTest {
mAccessPointsChangedLatch = new CountDownLatch(1);
tracker.mReceiver.onReceive(mContext, new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));
- mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+ assertTrue(mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
assertThat(tracker.getAccessPoints()).isEmpty();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index 12d3106cfe61..706d0c0f51e5 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -16,6 +16,9 @@
package com.android.settingslib;
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
+
+import static com.android.settingslib.Utils.STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Matchers.eq;
@@ -30,6 +33,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.location.LocationManager;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Secure;
@@ -136,7 +140,7 @@ public class UtilsTest {
}
@Test
- public void testStorageManagerDaysToRetainUsesResources() {
+ public void testGetDefaultStorageManagerDaysToRetain_storageManagerDaysToRetainUsesResources() {
Resources resources = mock(Resources.class);
when(resources.getInteger(
eq(
@@ -149,6 +153,12 @@ public class UtilsTest {
assertThat(Utils.getDefaultStorageManagerDaysToRetain(resources)).isEqualTo(60);
}
+ @Test
+ public void testIsStorageManagerEnabled_UsesSystemProperties() {
+ SystemProperties.set(STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY, "false");
+ assertThat(Utils.isStorageManagerEnabled(mContext)).isTrue();
+ }
+
private static ArgumentMatcher<Intent> actionMatches(String expected) {
return intent -> TextUtils.equals(expected, intent.getAction());
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java
index ebafc594c122..017d37388340 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java
@@ -31,7 +31,6 @@ import android.content.SharedPreferences;
import android.util.Pair;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.google.common.truth.Platform;
import org.junit.Before;
import org.junit.Test;
@@ -160,18 +159,23 @@ public class SharedPreferenceLoggerTest {
}
private ArgumentMatcher<Pair<Integer, Object>> pairMatches(int tag, Class clazz) {
- return pair -> pair.first == tag && Platform.isInstanceOfType(pair.second, clazz);
+ return pair -> pair.first == tag && isInstanceOfType(pair.second, clazz);
}
private ArgumentMatcher<Pair<Integer, Object>> pairMatches(int tag, boolean bool) {
return pair -> pair.first == tag
- && Platform.isInstanceOfType(pair.second, Integer.class)
+ && isInstanceOfType(pair.second, Integer.class)
&& pair.second.equals((bool ? 1 : 0));
}
private ArgumentMatcher<Pair<Integer, Object>> pairMatches(int tag, int val) {
return pair -> pair.first == tag
- && Platform.isInstanceOfType(pair.second, Integer.class)
+ && isInstanceOfType(pair.second, Integer.class)
&& pair.second.equals(val);
}
+
+ /** Returns true if the instance is assignable to the type Clazz. */
+ private static boolean isInstanceOfType(Object instance, Class<?> clazz) {
+ return clazz.isInstance(instance);
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java
index 9b5da4ae1f95..ccd2f538c731 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java
@@ -17,15 +17,22 @@
package com.android.settingslib.notification;
import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.Fragment;
+import android.app.NotificationManager;
import android.content.Context;
+import android.content.res.Resources;
import android.net.Uri;
import android.service.notification.Condition;
import android.view.LayoutInflater;
@@ -46,7 +53,11 @@ public class EnableZenModeDialogTest {
@Mock
private Context mContext;
@Mock
+ private Resources mResources;
+ @Mock
private Fragment mFragment;
+ @Mock
+ private NotificationManager mNotificationManager;
private Context mShadowContext;
private LayoutInflater mLayoutInflater;
@@ -58,6 +69,7 @@ public class EnableZenModeDialogTest {
MockitoAnnotations.initMocks(this);
mShadowContext = RuntimeEnvironment.application;
when(mContext.getApplicationContext()).thenReturn(mContext);
+ when(mContext.getResources()).thenReturn(mResources);
when(mFragment.getContext()).thenReturn(mShadowContext);
mLayoutInflater = LayoutInflater.from(mShadowContext);
@@ -67,6 +79,10 @@ public class EnableZenModeDialogTest {
mController.mForeverId = Condition.newId(mContext).appendPath("forever").build();
when(mContext.getString(com.android.internal.R.string.zen_mode_forever))
.thenReturn("testSummary");
+ NotificationManager.Policy alarmsEnabledPolicy = new NotificationManager.Policy(
+ NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS, 0, 0, 0);
+ doReturn(alarmsEnabledPolicy).when(mNotificationManager).getNotificationPolicy();
+ mController.mNotificationManager = mNotificationManager;
mController.getContentView();
// these methods use static calls to ZenModeConfig which would normally fail in robotests,
@@ -141,4 +157,38 @@ public class EnableZenModeDialogTest {
assertFalse(mController.getConditionTagAt(
EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX).rb.isChecked());
}
+
+ @Test
+ public void testNoAlarmWarning() {
+ // setup alarm
+ long now = System.currentTimeMillis();
+ doReturn(now + 100000).when(mController).getNextAlarm();
+ doReturn("").when(mController).getTime(anyLong(), anyLong());
+
+ // allow alarms
+ when(mNotificationManager.getNotificationPolicy()).thenReturn(
+ new NotificationManager.Policy(
+ NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS, 0, 0, 0));
+
+ // alarm warning should be null
+ assertNull(mController.computeAlarmWarningText(null));
+ }
+
+ @Test
+ public void testAlarmWarning() {
+ // setup alarm
+ long now = System.currentTimeMillis();
+ doReturn(now + 1000000).when(mController).getNextAlarm();
+ doReturn("").when(mController).getTime(anyLong(), anyLong());
+
+ // don't allow alarms to bypass dnd
+ when(mNotificationManager.getNotificationPolicy()).thenReturn(
+ new NotificationManager.Policy(0, 0, 0, 0));
+
+ // return a string if mResources is asked to retrieve a string
+ when(mResources.getString(anyInt(), anyString())).thenReturn("");
+
+ // alarm warning should NOT be null
+ assertNotNull(mController.computeAlarmWarningText(null));
+ }
} \ No newline at end of file
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 91957e1ff05c..ad422d8011d7 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -76,11 +76,10 @@ public class SettingsHelper {
*/
private static final ArraySet<String> sBroadcastOnRestore;
static {
- sBroadcastOnRestore = new ArraySet<String>(5);
+ sBroadcastOnRestore = new ArraySet<String>(4);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_VR_LISTENERS);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
- sBroadcastOnRestore.add(Settings.Secure.ENABLED_INPUT_METHODS);
sBroadcastOnRestore.add(Settings.Global.BLUETOOTH_ON);
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 1551b8e2eea9..1e8c523a9e34 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -870,6 +870,12 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
GlobalSettingsProto.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING);
+ dumpSetting(s, p,
+ Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT,
+ GlobalSettingsProto.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT);
+ dumpSetting(s, p,
+ Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS,
+ GlobalSettingsProto.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS);
// Settings.Global.SHOW_PROCESSES intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.Global.LOW_POWER_MODE,
@@ -1055,6 +1061,9 @@ class SettingsProtoDumpUtil {
Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED,
GlobalSettingsProto.CHAINED_BATTERY_ATTRIBUTION_ENABLED);
dumpSetting(s, p,
+ Global.HIDDEN_API_BLACKLIST_EXEMPTIONS,
+ GlobalSettingsProto.HIDDEN_API_BLACKLIST_EXEMPTIONS);
+ dumpSetting(s, p,
Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION,
GlobalSettingsProto.MULTI_SIM_VOICE_CALL_SUBSCRIPTION);
dumpSetting(s, p,
@@ -1123,6 +1132,9 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Global.SHOW_MUTE_IN_CRASH_DIALOG,
GlobalSettingsProto.SHOW_MUTE_IN_CRASH_DIALOG);
+ dumpSetting(s, p,
+ Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION,
+ GlobalSettingsProto.SHOW_ZEN_UPGRADE_NOTIFICATION);
// Please insert new settings using the same order as in Settings.Global.
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 85a579d2808d..87ea38202e2d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1591,6 +1591,7 @@ public class SettingsProvider extends ContentProvider {
private boolean isGlobalOrSecureSettingRestrictedForUser(String setting, int userId,
String value, int callingUid) {
String restriction;
+ boolean checkAllUser = false;
switch (setting) {
case Settings.Secure.LOCATION_MODE:
// Note LOCATION_MODE will be converted into LOCATION_PROVIDERS_ALLOWED
@@ -1656,6 +1657,12 @@ public class SettingsProvider extends ContentProvider {
restriction = UserManager.DISALLOW_AMBIENT_DISPLAY;
break;
+ case Global.LOCATION_GLOBAL_KILL_SWITCH:
+ if ("0".equals(value)) return false;
+ restriction = UserManager.DISALLOW_CONFIG_LOCATION;
+ checkAllUser = true;
+ break;
+
default:
if (setting != null && setting.startsWith(Settings.Global.DATA_ROAMING)) {
if ("0".equals(value)) return false;
@@ -1665,7 +1672,11 @@ public class SettingsProvider extends ContentProvider {
return false;
}
- return mUserManager.hasUserRestriction(restriction, UserHandle.of(userId));
+ if (checkAllUser) {
+ return mUserManager.hasUserRestrictionOnAnyUser(restriction);
+ } else {
+ return mUserManager.hasUserRestriction(restriction, UserHandle.of(userId));
+ }
}
private int resolveOwningUserIdForSecureSettingLocked(int userId, String setting) {
diff --git a/packages/SimAppDialog/Android.mk b/packages/SimAppDialog/Android.mk
new file mode 100644
index 000000000000..00a2e60b29f4
--- /dev/null
+++ b/packages/SimAppDialog/Android.mk
@@ -0,0 +1,18 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := SimAppDialog
+LOCAL_CERTIFICATE := platform
+
+
+LOCAL_STATIC_ANDROID_LIBRARIES := \
+ android-support-v4
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+include frameworks/opt/setupwizard/library/common-platform-deprecated.mk
+
+include $(BUILD_PACKAGE)
diff --git a/core/java/android/security/keymaster/KeyCharacteristics.aidl b/packages/SimAppDialog/AndroidManifest.xml
index 32e75ad267b2..873f6c5bac54 100644
--- a/core/java/android/security/keymaster/KeyCharacteristics.aidl
+++ b/packages/SimAppDialog/AndroidManifest.xml
@@ -1,5 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -13,8 +15,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package android.security.keymaster;
-
-/* @hide */
-parcelable KeyCharacteristics cpp_header "keystore/KeyCharacteristics.h";
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.simappdialog">
+ <application android:label="@string/app_name">
+ <activity
+ android:name=".InstallCarrierAppActivity"
+ android:exported="true"
+ android:permission="android.permission.NETWORK_SETTINGS"
+ android:theme="@style/SuwThemeGlif.Light">
+ </activity>
+ </application>
+</manifest>
diff --git a/packages/SimAppDialog/res/drawable/ic_signal_cellular_alt_rounded_24px.xml b/packages/SimAppDialog/res/drawable/ic_signal_cellular_alt_rounded_24px.xml
new file mode 100644
index 000000000000..85896e8a2687
--- /dev/null
+++ b/packages/SimAppDialog/res/drawable/ic_signal_cellular_alt_rounded_24px.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="21dp"
+ android:height="22dp"
+ android:viewportWidth="21"
+ android:viewportHeight="22">
+
+ <group
+ android:translateX="-196.000000"
+ android:translateY="-77.000000">
+ <group
+ android:translateX="190.000000"
+ android:translateY="72.000000">
+ <path
+ android:fillType="evenOdd"
+ android:strokeWidth="1"
+ android:pathData="M 0 0 H 32 V 32 H 0 V 0 Z"/>
+ <group
+ android:translateX="6.666667"
+ android:translateY="5.333333">
+ <path
+ android:fillColor="#4285F4"
+ android:strokeWidth="1"
+ android:pathData="M 17 0 L 19 0 Q 20 0 20 1 L 20 20.3333333 Q 20 21.3333333 19 21.3333333 L 17 21.3333333 Q 16 21.3333333 16 20.3333333 L 16 1 Q 16 0 17 0 Z"/>
+ <path
+ android:fillColor="#4285F4"
+ android:strokeWidth="1"
+ android:pathData="M 1 13.3333333 L 3 13.3333333 Q 4 13.3333333 4 14.3333333 L 4 20.3333333 Q 4 21.3333333 3 21.3333333 L 1 21.3333333 Q 0 21.3333333 0 20.3333333 L 0 14.3333333 Q 0 13.3333333 1 13.3333333 Z"/>
+ <path
+ android:fillColor="#4285F4"
+ android:strokeWidth="1"
+ android:pathData="M 9 6.66666667 L 11 6.66666667 Q 12 6.66666667 12 7.66666667 L 12 20.33333337 Q 12 21.33333337 11 21.33333337 L 9 21.33333337 Q 8 21.33333337 8 20.33333337 L 8 7.66666667 Q 8 6.66666667 9 6.66666667 Z"/>
+ </group>
+ </group>
+ </group>
+</vector> \ No newline at end of file
diff --git a/packages/SimAppDialog/res/drawable/placeholder.xml b/packages/SimAppDialog/res/drawable/placeholder.xml
new file mode 100644
index 000000000000..53eee7437c16
--- /dev/null
+++ b/packages/SimAppDialog/res/drawable/placeholder.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<!-- TODO(b/72511181): replace when illustration is finished -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="270dp"
+ android:height="270dp"
+ android:viewportHeight="270.0"
+ android:viewportWidth="270.0">
+ <path android:fillColor="#E8EAED"
+ android:pathData="M183.54,265H84.88c-7.63,0 -13.81,-6.18 -13.81,-13.81V18.81C71.07,11.18 77.25,5 84.88,5h98.66c7.63,0 13.81,6.18 13.81,13.81v232.38C197.35,258.82 191.17,265 183.54,265z"/>
+ <path android:fillColor="#BDC1C6"
+ android:pathData="M183.54,6.63c6.72,0 12.18,5.46 12.18,12.18v232.38c0,6.72 -5.46,12.18 -12.18,12.18H84.88c-6.72,0 -12.18,-5.46 -12.18,-12.18V18.81c0,-6.72 5.46,-12.18 12.18,-12.18H183.54M183.54,5H84.88c-7.63,0 -13.81,6.18 -13.81,13.81v232.38c0,7.63 6.18,13.81 13.81,13.81h98.66c7.63,0 13.81,-6.18 13.81,-13.81V18.81C197.35,11.18 191.17,5 183.54,5L183.54,5z"/>
+ <path android:fillColor="#FFFFFF"
+ android:pathData="M186.34,243.74H82.08c-2.41,0 -4.36,-1.95 -4.36,-4.36V30.61c0,-2.41 1.95,-4.36 4.36,-4.36h104.26c2.41,0 4.36,1.95 4.36,4.36v208.78C190.7,241.79 188.75,243.74 186.34,243.74z"/>
+ <path android:fillColor="#BDC1C6"
+ android:pathData="M156.07,254.78h-43.72c-0.65,0 -1.18,-0.53 -1.18,-1.18v-0.08c0,-0.65 0.53,-1.18 1.18,-1.18h43.72c0.65,0 1.18,0.53 1.18,1.18v0.08C157.25,254.25 156.72,254.78 156.07,254.78z"/>
+ <path android:fillColor="#BDC1C6"
+ android:pathData="M156.07,17.67h-43.72c-0.65,0 -1.18,-0.53 -1.18,-1.18V16.4c0,-0.65 0.53,-1.18 1.18,-1.18l43.72,0c0.65,0 1.18,0.53 1.18,1.18v0.08C157.25,17.14 156.72,17.67 156.07,17.67z"/>
+ <path android:fillColor="#BDC1C6"
+ android:pathData="M197.85,84.16h-0.5V67.51h0.5c0.6,0 1.08,0.48 1.08,1.08v14.5C198.93,83.68 198.45,84.16 197.85,84.16z"/>
+ <path android:fillColor="#BDC1C6"
+ android:pathData="M197.41,136.45h-0.06v-32.87h0.06c0.84,0 1.52,0.68 1.52,1.52v29.84C198.93,135.77 198.25,136.45 197.41,136.45z"/>
+ <path android:fillColor="#BDC1C6"
+ android:pathData="M119.3,74.73l2.71,2.71c6.74,-6.74 17.67,-6.74 24.4,0l2.71,-2.71C140.89,66.49 127.54,66.49 119.3,74.73zM130.15,85.57l4.07,4.07l4.07,-4.07C136.04,83.33 132.39,83.33 130.15,85.57zM124.72,80.15l2.71,2.71c3.74,-3.74 9.82,-3.74 13.56,0l2.71,-2.71C138.46,74.91 129.96,74.91 124.72,80.15z"/>
+ <path android:fillColor="#BDC1C6"
+ android:pathData="M143.7,179h-1.36v-2.71h-2.71V179h-10.85v-2.71h-2.71V179h-1.36c-1.5,0 -2.7,1.21 -2.7,2.71l-0.01,18.98c0,1.5 1.21,2.71 2.71,2.71h18.98c1.5,0 2.71,-1.21 2.71,-2.71v-18.98C146.41,180.22 145.2,179 143.7,179zM143.7,200.7h-18.98v-14.91h18.98V200.7zM127.43,188.49h6.78v6.78h-6.78V188.49z"/>
+ <path android:fillColor="#BDC1C6"
+ android:pathData="M146.41,144.49v-18.98c0,-1.5 -1.21,-2.71 -2.71,-2.71h-18.98c-1.5,0 -2.71,1.21 -2.71,2.71v18.98c0,1.5 1.21,2.71 2.71,2.71h18.98C145.2,147.2 146.41,145.99 146.41,144.49zM129.47,137.03l3.39,4.07l4.75,-6.11l6.1,8.13h-18.98L129.47,137.03z"/>
+</vector>
diff --git a/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml b/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml
new file mode 100644
index 000000000000..0462a9365c90
--- /dev/null
+++ b/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<com.android.setupwizardlib.GlifLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/setup_wizard_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:icon="@drawable/ic_signal_cellular_alt_rounded_24px"
+ app:suwHeaderText="@string/install_carrier_app_title"
+ app:suwFooter="@layout/install_carrier_app_footer">
+
+ <LinearLayout
+ style="@style/SuwContentFrame"
+ android:id="@+id/content_frame"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/install_carrier_app_description"
+ style="@style/SuwDescription.Glif"
+ android:text="@string/install_carrier_app_description_default"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <com.android.setupwizardlib.view.FillContentLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+
+ <!-- TODO(b/72511181): final illo and content description update -->
+ <ImageView
+ android:src="@drawable/placeholder"
+ style="@style/SuwContentIllustration"
+ android:contentDescription="@null"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+
+ </com.android.setupwizardlib.view.FillContentLayout>
+ </LinearLayout>
+
+</com.android.setupwizardlib.GlifLayout>
diff --git a/packages/SimAppDialog/res/layout/install_carrier_app_footer.xml b/packages/SimAppDialog/res/layout/install_carrier_app_footer.xml
new file mode 100644
index 000000000000..10dcb77a6584
--- /dev/null
+++ b/packages/SimAppDialog/res/layout/install_carrier_app_footer.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+
+<com.android.setupwizardlib.view.ButtonBarLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/footer"
+ style="@style/SuwGlifButtonBar.Stackable"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <Button
+ android:id="@+id/skip_button"
+ style="@style/SuwGlifButton.Secondary"
+ android:text="@string/install_carrier_app_defer_action"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+ <Button
+ android:id="@+id/download_button"
+ style="@style/SuwGlifButton.Primary"
+ android:text="@string/install_carrier_app_download_action"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+</com.android.setupwizardlib.view.ButtonBarLayout>
diff --git a/packages/SimAppDialog/res/values/strings.xml b/packages/SimAppDialog/res/values/strings.xml
new file mode 100644
index 000000000000..0c3930dfdf08
--- /dev/null
+++ b/packages/SimAppDialog/res/values/strings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- TODO character limits -->
+ <!-- The name of this application -->
+ <string name="app_name">Sim App Dialog</string>
+ <!-- Install Carrier App Activity -->
+ <!-- Title of screen asking user to download the carrier app to match the inserted SIM card -->
+ <string name="install_carrier_app_title">Activate mobile service</string>
+ <!-- Description of screen asking user to download the carrier app to match the inserted SIM card if we know the name of the carrier-->
+ <string name="install_carrier_app_description">To get your new SIM working properly, you\'ll
+ need to install the <xliff:g name="carrier_name" example="Project Fi">%1$s</xliff:g> app
+ </string>
+ <!-- Description of screen asking user to download the carrier app to match the inserted SIM card if we don't know the name of the carrier-->
+ <string name="install_carrier_app_description_default">To get your new SIM working properly,
+ you\'ll need to install the carrier app
+ </string>
+ <!-- Name of the button used to defer downloading the carrier app -->
+ <string name="install_carrier_app_defer_action">Not now</string>
+ <!-- Name of the button for downloading the carrier app -->
+ <string name="install_carrier_app_download_action">Download app</string>
+</resources> \ No newline at end of file
diff --git a/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java b/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java
new file mode 100644
index 000000000000..9e9b80d39ed7
--- /dev/null
+++ b/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+package com.android.simappdialog;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.setupwizardlib.util.WizardManagerHelper;
+
+/**
+ * Activity that gives a user the choice to download the SIM app or defer until a later time
+ *
+ * Will finish with result {@link #DEFER_RESULT} on defer button press or {@link #DOWNLOAD_RESULT}
+ * if the download button is pressed
+ *
+ * Can display the carrier app name if its passed into the intent with key
+ * {@link #BUNDLE_KEY_CARRIER_NAME}
+ */
+public class InstallCarrierAppActivity extends Activity implements View.OnClickListener {
+ /**
+ * Key for the carrier app name that will be displayed as the app to download. If unset, a
+ * default description will be used
+ */
+ public static final String BUNDLE_KEY_CARRIER_NAME = "carrier_name";
+ /** Result code when the defer button is pressed */
+ public static final int DEFER_RESULT = 1;
+ /** Result code when the download button is pressed */
+ public static final int DOWNLOAD_RESULT = 2;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ // Setup theme for aosp/pixel
+ setTheme(
+ WizardManagerHelper.getThemeRes(
+ SystemProperties.get("setupwizard.theme"),
+ R.style.SuwThemeGlif_Light
+ )
+ );
+
+ super.onCreate(icicle);
+ setContentView(R.layout.install_carrier_app_activity);
+
+ Button notNowButton = findViewById(R.id.skip_button);
+ notNowButton.setOnClickListener(this);
+
+ Button downloadButton = findViewById(R.id.download_button);
+ downloadButton.setOnClickListener(this);
+
+ // Include carrier name in description text if its present in the intent
+ Intent intent = getIntent();
+ if (intent != null) {
+ String carrierName = intent.getStringExtra(BUNDLE_KEY_CARRIER_NAME);
+ if (!TextUtils.isEmpty(carrierName)) {
+ TextView subtitle = findViewById(R.id.install_carrier_app_description);
+ subtitle.setText(getString(R.string.install_carrier_app_description, carrierName));
+ }
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.skip_button:
+ finish(DEFER_RESULT);
+ break;
+ case R.id.download_button:
+ finish(DOWNLOAD_RESULT);
+ break;
+ }
+ }
+
+ private void finish(int resultCode) {
+ setResult(resultCode);
+ finish();
+ }
+}
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index af6dd77224c4..7c97ca6103aa 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -2,19 +2,23 @@ set noparent
dsandler@google.com
+adamcohen@google.com
asc@google.com
ashaikh@google.com
beverlyt@google.com
cinek@google.com
cwren@google.com
+dupin@google.com
evanlaird@google.com
jmonk@google.com
jaggies@google.com
jjaggi@google.com
juliacr@google.com
-dupin@google.com
madym@google.com
+ngmatthew@google.com
roosa@google.com
shahrk@google.com
+sunnygoyal@google.com
+twickham@google.com
winsonc@google.com
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
index faa2c17b63bf..31635a507d6f 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
@@ -33,6 +33,23 @@
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/widget_vertical_padding"
android:orientation="vertical">
+ <TextView
+ android:id="@+id/logout"
+ android:layout_height="@dimen/logout_button_layout_height"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="@dimen/logout_button_margin_bottom"
+ android:gravity="center"
+ android:paddingLeft="@dimen/logout_button_padding_horizontal"
+ android:paddingRight="@dimen/logout_button_padding_horizontal"
+ android:background="@drawable/logout_button_background"
+ android:fontFamily="roboto-medium"
+ android:textAllCaps="true"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="13sp"
+ android:text="@*android:string/global_action_logout" />
+
<RelativeLayout
android:id="@+id/keyguard_clock_container"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step.png
new file mode 100644
index 000000000000..d7f94497409a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step_dark.png
new file mode 100644
index 000000000000..7c657036c4fc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 000000000000..eea819a1109e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 000000000000..504ceb79fba0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 000000000000..8e7d8cba1a4e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 000000000000..456a68f0200c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 000000000000..fb854ec51296
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 000000000000..75d184a1f739
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 000000000000..9e0af28efced
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 000000000000..7c00bd5d1f30
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 000000000000..81b44665e078
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 000000000000..724aa9e19e41
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 000000000000..7ba0d1b1b7d3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 000000000000..a175ccb5b4f8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 000000000000..45ce1d4b62b6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 000000000000..6da0c9e6bd5e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 000000000000..71e89595f35d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 000000000000..bb7ae2637fcc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 000000000000..32b9ded52836
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 000000000000..ed1949c71438
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 000000000000..2d62a80a63ba
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 000000000000..a52e5b10fcf3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step.png
new file mode 100644
index 000000000000..d888869d2b0f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step_dark.png
new file mode 100644
index 000000000000..dc3b25c0d347
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 000000000000..d4e5a94fca1b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 000000000000..0e693f7d6e9a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 000000000000..07577999201f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 000000000000..4f07ec1a9797
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step.png
new file mode 100644
index 000000000000..ba5b457a0bfa
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step_dark.png
new file mode 100644
index 000000000000..a55ea1d5b1ab
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 000000000000..407ef28a3f2a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 000000000000..39cfbf2afb48
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 000000000000..a7fd3a69e98c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 000000000000..f2a1255c3570
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step.png
new file mode 100644
index 000000000000..5a7eec6502af
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step_dark.png
new file mode 100644
index 000000000000..f7abb54f974f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 000000000000..a1f44dc598b2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 000000000000..175a9aefa463
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 000000000000..0fb93ca2a18d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 000000000000..1052940af382
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step.png
new file mode 100644
index 000000000000..d13c730d4f7a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step_dark.png
new file mode 100644
index 000000000000..31c602e8d2d6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 000000000000..ddbcb07dacfb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 000000000000..ce91fcbb24b2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 000000000000..c606a58c247e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 000000000000..c2a5fef89799
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/car_ic_hvac.xml b/packages/SystemUI/res/drawable/car_ic_hvac.xml
new file mode 100644
index 000000000000..bdc44b38a176
--- /dev/null
+++ b/packages/SystemUI/res/drawable/car_ic_hvac.xml
@@ -0,0 +1,51 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="37dp"
+ android:height="31dp"
+ android:viewportWidth="37"
+ android:viewportHeight="31">
+
+ <group
+ android:translateX="-4.000000"
+ android:translateY="-6.000000">
+ <group
+ android:translateX="5.000000"
+ android:translateY="5.000000">
+ <path
+ android:fillType="evenOdd"
+ android:strokeColor="#FAFAFA"
+ android:strokeWidth="3.5"
+ android:pathData="M0.320769938,6.07518051 C6.46754647,1.46509811 12.4222362,1.46509811
+18.1848392,6.07518051 C23.9474422,10.6852629 29.3258717,10.4931761
+34.3201276,5.49892021" />
+ <path
+ android:fillType="evenOdd"
+ android:strokeColor="#FAFAFA"
+ android:strokeWidth="3.5"
+ android:pathData="M0.320769938,17.0751805 C6.46754647,12.4650981 12.4222362,12.4650981
+18.1848392,17.0751805 C23.9474422,21.6852629 29.3258717,21.4931761
+34.3201276,16.4989202" />
+ <path
+ android:fillType="evenOdd"
+ android:strokeColor="#FAFAFA"
+ android:strokeWidth="3.5"
+ android:pathData="M0.320769938,28.0751805 C6.46754647,23.4650981 12.4222362,23.4650981
+18.1848392,28.0751805 C23.9474422,32.6852629 29.3258717,32.4931761
+34.3201276,27.4989202" />
+ </group>
+ </group>
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/car_ic_notification.xml b/packages/SystemUI/res/drawable/car_ic_notification.xml
new file mode 100644
index 000000000000..61d937b90d04
--- /dev/null
+++ b/packages/SystemUI/res/drawable/car_ic_notification.xml
@@ -0,0 +1,28 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="56dp"
+ android:height="56dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M24 44c2.21 0 4-1.79 4-4h-8c0 2.21 1.79 4 4
+4zm12-12V22c0-6.15-3.27-11.28-9-12.64V8c0-1.66-1.34-3-3-3s-3 1.34-3 3v1.36c-5.73
+1.36-9 6.49-9 12.64v10l-4 4v2h32v-2l-4-4zm-4 2H16V22c0-4.97 3.03-9 8-9s8 4.03 8
+9v12z" />
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/car_ic_overview.xml b/packages/SystemUI/res/drawable/car_ic_overview.xml
new file mode 100644
index 000000000000..4651dcb3a229
--- /dev/null
+++ b/packages/SystemUI/res/drawable/car_ic_overview.xml
@@ -0,0 +1,28 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="56dp"
+ android:height="56dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+
+ <path
+ android:pathData="M0 0h48v48H0z" />
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M24 4C12.95 4 4 12.95 4 24s8.95 20 20 20 20-8.95 20-20S35.05 4 24 4zm0 36c-8.82
+0-16-7.18-16-16S15.18 8 24 8s16 7.18 16 16-7.18 16-16 16z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_lock_lockdown.xml b/packages/SystemUI/res/drawable/ic_lock_lockdown.xml
new file mode 100644
index 000000000000..b517fc89e094
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_lock_lockdown.xml
@@ -0,0 +1,25 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+
+ <path
+ android:fillColor="#757575"
+ android:pathData="M18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 7.0,6.0l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM12.0,17.0c-1.1,0.0 -2.0,-0.9 -2.0,-2.0s0.9,-2.0 2.0,-2.0c1.1,0.0 2.0,0.9 2.0,2.0S13.1,17.0 12.0,17.0zM15.1,8.0L8.9,8.0L8.9,6.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1L15.1,8.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/logout_button_background.xml b/packages/SystemUI/res/drawable/logout_button_background.xml
new file mode 100644
index 000000000000..eafd663f19d9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/logout_button_background.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ 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
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/logout_button_bg_color"/>
+ <corners android:radius="@dimen/logout_button_corner_radius"/>
+</shape>
diff --git a/packages/SystemUI/res/drawable/smart_reply_button_background.xml b/packages/SystemUI/res/drawable/smart_reply_button_background.xml
index 1cd1451008b4..c5ac67beb521 100644
--- a/packages/SystemUI/res/drawable/smart_reply_button_background.xml
+++ b/packages/SystemUI/res/drawable/smart_reply_button_background.xml
@@ -20,7 +20,9 @@
android:color="@color/notification_ripple_untinted_color">
<item>
<shape android:shape="rectangle">
- <corners android:radius="@dimen/smart_reply_button_corner_radius"/>
+ <!-- Use non-zero corner radius to work around b/73285195. The actual corner radius is
+ set dynamically at runtime in SmartReplyView. -->
+ <corners android:radius="1dp"/>
<solid android:color="@color/smart_reply_button_background"/>
</shape>
</item>
diff --git a/packages/SystemUI/res/layout/car_facet_button.xml b/packages/SystemUI/res/layout/car_facet_button.xml
new file mode 100644
index 000000000000..f432d366e926
--- /dev/null
+++ b/packages/SystemUI/res/layout/car_facet_button.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/car_facet_button"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:animateLayoutChanges="true"
+ android:orientation="vertical">
+
+ <com.android.keyguard.AlphaOptimizedImageButton
+ android:id="@+id/car_nav_button_icon"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:animateLayoutChanges="true"
+ android:background="@android:color/transparent"
+ android:scaleType="fitCenter">
+ </com.android.keyguard.AlphaOptimizedImageButton>
+
+ <com.android.keyguard.AlphaOptimizedImageButton
+ android:id="@+id/car_nav_button_more_icon"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:animateLayoutChanges="true"
+ android:background="@android:color/transparent"
+ android:scaleType="fitCenter">
+ </com.android.keyguard.AlphaOptimizedImageButton>
+
+ </LinearLayout>
+</merge>
diff --git a/packages/SystemUI/res/layout/car_left_navigation_bar.xml b/packages/SystemUI/res/layout/car_left_navigation_bar.xml
new file mode 100644
index 000000000000..866b5a5b0ec7
--- /dev/null
+++ b/packages/SystemUI/res/layout/car_left_navigation_bar.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<com.android.systemui.statusbar.car.CarNavigationBarView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:orientation="vertical"
+ android:background="@drawable/system_bar_background">
+
+ <LinearLayout
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:id="@+id/nav_buttons"
+ android:orientation="vertical"
+ android:gravity="top"
+ android:paddingTop="30dp"
+ android:layout_weight="1"
+ android:background="@drawable/system_bar_background"
+ android:animateLayoutChanges="true">
+
+ <com.android.systemui.statusbar.car.CarNavigationButton
+ android:id="@+id/home"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;end"
+ android:src="@drawable/car_ic_overview"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingTop="30dp"
+ android:paddingBottom="30dp"
+ />
+
+ <com.android.systemui.statusbar.car.CarNavigationButton
+ android:id="@+id/hvac"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ systemui:intent="intent:#Intent;action=android.car.intent.action.SHOW_HVAC_CONTROLS;end"
+ systemui:broadcast="true"
+ android:src="@drawable/car_ic_hvac"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingTop="30dp"
+ android:paddingBottom="30dp"
+ />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="bottom"
+ android:orientation="vertical">
+
+ <com.android.keyguard.AlphaOptimizedImageButton
+ android:id="@+id/notifications"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:src="@drawable/car_ic_notification"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingTop="20dp"
+ android:paddingBottom="20dp"
+ android:alpha="0.7"
+ />
+
+ <com.android.systemui.statusbar.policy.Clock
+ android:id="@+id/clock"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:singleLine="true"
+ android:paddingStart="@dimen/status_bar_clock_starting_padding"
+ android:paddingEnd="@dimen/status_bar_clock_end_padding"
+ android:gravity="center_horizontal"
+ android:paddingBottom="20dp"
+ />
+
+ <Space
+ android:layout_height="10dp"
+ android:layout_width="match_parent"/>
+
+ </LinearLayout>
+
+</com.android.systemui.statusbar.car.CarNavigationBarView>
diff --git a/packages/SystemUI/res/layout/car_navigation_bar.xml b/packages/SystemUI/res/layout/car_navigation_bar.xml
index 999dbac3b8bc..4666c604dc9c 100644
--- a/packages/SystemUI/res/layout/car_navigation_bar.xml
+++ b/packages/SystemUI/res/layout/car_navigation_bar.xml
@@ -19,34 +19,80 @@
<com.android.systemui.statusbar.car.CarNavigationBarView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:layout_width="match_parent"
- android:gravity="center"
android:background="@drawable/system_bar_background">
- <!-- phone.NavigationBarView has rot0 and rot90 but we expect the car head unit to have a fixed
- rotation so skip this level of the heirarchy.
- -->
<LinearLayout
android:layout_height="match_parent"
- android:layout_width="@dimen/car_navigation_bar_width"
+ android:layout_width="wrap_content"
android:orientation="horizontal"
- android:clipChildren="false"
- android:clipToPadding="false"
android:id="@+id/nav_buttons"
+ android:gravity="left"
+ android:paddingLeft="30dp"
+ android:layout_weight="1"
android:animateLayoutChanges="true">
- <!-- Buttons get populated here from a car_arrays.xml. -->
+ <com.android.systemui.statusbar.car.CarNavigationButton
+ android:id="@+id/home"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;end"
+ android:src="@drawable/car_ic_overview"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingLeft="30dp"
+ android:paddingRight="30dp"
+ />
+
+ <com.android.systemui.statusbar.car.CarNavigationButton
+ android:id="@+id/hvac"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ systemui:intent="intent:#Intent;action=android.car.intent.action.SHOW_HVAC_CONTROLS;end"
+ systemui:broadcast="true"
+ android:src="@drawable/car_ic_hvac"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingLeft="30dp"
+ android:paddingRight="30dp"
+ />
</LinearLayout>
- <!-- lights out layout to match exactly -->
<LinearLayout
+ android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:orientation="horizontal"
- android:id="@+id/lights_out"
- android:visibility="gone">
- <!-- Must match nav_buttons. -->
+ android:layout_weight="1"
+ android:gravity="right"
+ android:orientation="horizontal">
+
+ <com.android.keyguard.AlphaOptimizedImageButton
+ android:id="@+id/notifications"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:src="@drawable/car_ic_notification"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingLeft="20dp"
+ android:paddingRight="20dp"
+ android:alpha="0.7"
+ />
+
+ <com.android.systemui.statusbar.policy.Clock
+ android:id="@+id/clock"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:singleLine="true"
+ android:paddingStart="@dimen/status_bar_clock_starting_padding"
+ android:paddingEnd="@dimen/status_bar_clock_end_padding"
+ android:gravity="center_vertical"
+ android:paddingRight="20dp"
+ />
+
+ <Space
+ android:layout_width="10dp"
+ android:layout_height="match_parent"/>
+
</LinearLayout>
</com.android.systemui.statusbar.car.CarNavigationBarView>
+
diff --git a/packages/SystemUI/res/layout/car_navigation_button.xml b/packages/SystemUI/res/layout/car_navigation_button.xml
index 767764694fae..4062eb8068fa 100644
--- a/packages/SystemUI/res/layout/car_navigation_button.xml
+++ b/packages/SystemUI/res/layout/car_navigation_button.xml
@@ -17,28 +17,13 @@
*/
-->
-<com.android.systemui.statusbar.car.CarNavigationButton
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- android:orientation="horizontal"
- android:background="?android:attr/selectableItemBackground">
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
<com.android.keyguard.AlphaOptimizedImageButton
- android:id="@+id/car_nav_button_icon"
- android:layout_height="match_parent"
- android:layout_width="@dimen/car_navigation_button_width"
- android:layout_centerInParent="true"
- android:animateLayoutChanges="true"
- android:scaleType="fitCenter">
+ android:id="@+id/car_nav_button_icon"
+ android:layout_height="wrap_content"
+ android:layout_width="@dimen/car_navigation_button_width"
+ android:layout_centerInParent="true"
+ android:animateLayoutChanges="true"
+ android:scaleType="fitCenter">
</com.android.keyguard.AlphaOptimizedImageButton>
-
- <com.android.keyguard.AlphaOptimizedImageButton
- android:id="@+id/car_nav_button_more_icon"
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- android:layout_centerVertical="true"
- android:layout_toRightOf="@+id/car_nav_button_icon"
- android:animateLayoutChanges="true"
- android:scaleType="fitCenter">
- </com.android.keyguard.AlphaOptimizedImageButton>
-</com.android.systemui.statusbar.car.CarNavigationButton>
+</merge>
diff --git a/packages/SystemUI/res/layout/car_right_navigation_bar.xml b/packages/SystemUI/res/layout/car_right_navigation_bar.xml
new file mode 100644
index 000000000000..99ab8021b43b
--- /dev/null
+++ b/packages/SystemUI/res/layout/car_right_navigation_bar.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<com.android.systemui.statusbar.car.CarNavigationBarView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:orientation="vertical"
+ android:background="@drawable/system_bar_background">
+
+ <LinearLayout
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:id="@+id/nav_buttons"
+ android:orientation="vertical"
+ android:gravity="top"
+ android:paddingTop="30dp"
+ android:layout_weight="1"
+ android:background="@drawable/system_bar_background"
+ android:animateLayoutChanges="true">
+
+ <com.android.systemui.statusbar.car.CarNavigationButton
+ android:id="@+id/home"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;end"
+ android:src="@drawable/car_ic_overview"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingTop="30dp"
+ android:paddingBottom="30dp"
+ />
+
+ <com.android.systemui.statusbar.car.CarNavigationButton
+ android:id="@+id/hvac"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ systemui:intent="intent:#Intent;action=android.car.intent.action.SHOW_HVAC_CONTROLS;end"
+ systemui:broadcast="true"
+ android:src="@drawable/car_ic_hvac"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingTop="30dp"
+ android:paddingBottom="30dp"
+ />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="bottom"
+ android:orientation="vertical">
+
+ <com.android.keyguard.AlphaOptimizedImageButton
+ android:id="@+id/notifications"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:src="@drawable/car_ic_notification"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingTop="20dp"
+ android:paddingBottom="20dp"
+ android:alpha="0.7"
+ />
+
+
+ <com.android.systemui.statusbar.policy.Clock
+ android:id="@+id/clock"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:singleLine="true"
+ android:paddingStart="@dimen/status_bar_clock_starting_padding"
+ android:paddingEnd="@dimen/status_bar_clock_end_padding"
+ android:gravity="center_horizontal"
+ android:paddingBottom="20dp"
+ />
+
+ <Space
+ android:layout_height="10dp"
+ android:layout_width="match_parent"/>
+
+ </LinearLayout>
+
+</com.android.systemui.statusbar.car.CarNavigationBarView>
diff --git a/packages/SystemUI/res/layout/menu_ime.xml b/packages/SystemUI/res/layout/menu_ime.xml
index 8078c4121424..24709478e076 100644
--- a/packages/SystemUI/res/layout/menu_ime.xml
+++ b/packages/SystemUI/res/layout/menu_ime.xml
@@ -41,6 +41,15 @@
android:scaleType="centerInside"
/>
<com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/rotate_suggestion"
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="2dp"
+ android:visibility="invisible"
+ android:scaleType="centerInside"
+ android:contentDescription="@string/accessibility_rotate_button"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView
android:id="@+id/accessibility_button"
android:layout_width="@dimen/navigation_extra_key_width"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 6b5bd1260acc..759d1ed0393f 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -30,14 +30,15 @@
<!-- Package Info -->
<RelativeLayout
android:layout_width="match_parent"
- android:layout_height="@dimen/notification_guts_header_height"
+ android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
- android:layout_marginTop="@*android:dimen/notification_header_padding_top" >
+ android:layout_marginTop="2dp" >
<ImageView
android:id="@+id/pkgicon"
android:layout_width="@dimen/notification_guts_header_height"
android:layout_height="@dimen/notification_guts_header_height"
+ android:layout_centerVertical="true"
android:layout_marginEnd="3dp" />
<TextView
android:id="@+id/pkgname"
@@ -74,8 +75,11 @@
android:id="@+id/info"
android:src="@drawable/ic_info"
android:tint="?android:attr/colorAccent"
- android:layout_width="@dimen/notification_guts_header_height"
- android:layout_height="@dimen/notification_guts_header_height"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="12dp"
+ android:layout_marginEnd="-12dp"
+ android:layout_centerVertical="true"
android:contentDescription="@string/notification_more_settings"
android:background="@drawable/ripple_drawable"
android:layout_alignParentEnd="true" />
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 97472a49187a..cf88adee7a62 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -71,23 +71,19 @@
android:singleLine="true" />
</LinearLayout>
- <FrameLayout
+ <View
+ android:id="@+id/qs_drag_handle_view"
android:layout_width="24dp"
- android:layout_height="match_parent" >
- <View
- android:id="@+id/qs_drag_handle_view"
- android:layout_width="match_parent"
- android:layout_height="4dp"
- android:layout_marginTop="28dp"
- android:background="@drawable/qs_footer_drag_handle" />
- </FrameLayout>
+ android:layout_height="4dp"
+ android:layout_gravity="center"
+ android:background="@drawable/qs_footer_drag_handle" />
- <LinearLayout
+ <com.android.keyguard.AlphaOptimizedLinearLayout
android:id="@+id/qs_footer_actions_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
- android:gravity="end" >
+ android:gravity="center_vertical|end" >
<com.android.systemui.statusbar.phone.MultiUserSwitch
android:id="@+id/multi_user_switch"
android:layout_width="48dp"
@@ -113,7 +109,7 @@
android:clipToPadding="false"
android:contentDescription="@string/accessibility_quick_settings_edit"
android:focusable="true"
- android:padding="16dp"
+ android:padding="15dp"
android:src="@drawable/ic_mode_edit"
android:tint="?android:attr/colorForeground"/>
@@ -131,6 +127,7 @@
android:layout_height="match_parent"
android:background="@drawable/ripple_drawable"
android:contentDescription="@string/accessibility_quick_settings_settings"
+ android:padding="15dp"
android:src="@drawable/ic_settings_16dp"
android:tint="?android:attr/colorForeground"/>
@@ -145,7 +142,7 @@
android:visibility="invisible"/>
</com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
- </LinearLayout>
+ </com.android.keyguard.AlphaOptimizedLinearLayout>
</LinearLayout>
</com.android.systemui.qs.QSFooterImpl>
diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml
index a3118b0a5d91..25b117fb2e33 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml
@@ -63,6 +63,7 @@
android:src="@drawable/screen_pinning_bg_circ" />
<ImageView
+ android:id="@+id/screen_pinning_back_icon"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingEnd="@dimen/screen_pinning_request_nav_side_padding"
@@ -105,6 +106,7 @@
android:src="@drawable/screen_pinning_bg_circ" />
<ImageView
+ android:id="@+id/screen_pinning_home_icon"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingEnd="@dimen/screen_pinning_request_nav_side_padding"
diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml
index 61fe906d65fc..37a1a90b6474 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml
@@ -59,6 +59,7 @@
android:src="@drawable/screen_pinning_bg_circ" />
<ImageView
+ android:id="@+id/screen_pinning_back_icon"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:scaleType="center"
@@ -99,6 +100,7 @@
android:src="@drawable/screen_pinning_bg_circ" />
<ImageView
+ android:id="@+id/screen_pinning_home_icon"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:scaleType="center"
diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml
index d1ca2ce5935c..bac02aa34ed9 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml
@@ -61,6 +61,7 @@
android:src="@drawable/screen_pinning_bg_circ" />
<ImageView
+ android:id="@+id/screen_pinning_back_icon"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:scaleType="center"
@@ -103,6 +104,7 @@
android:src="@drawable/screen_pinning_bg_circ" />
<ImageView
+ android:id="@+id/screen_pinning_home_icon"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:scaleType="center"
diff --git a/packages/SystemUI/res/layout/smart_reply_button.xml b/packages/SystemUI/res/layout/smart_reply_button.xml
index 4ac41d5cf6c3..3c6edcd8a917 100644
--- a/packages/SystemUI/res/layout/smart_reply_button.xml
+++ b/packages/SystemUI/res/layout/smart_reply_button.xml
@@ -16,17 +16,19 @@
~ limitations under the License
-->
+<!-- android:paddingHorizontal is set dynamically in SmartReplyView. -->
<Button xmlns:android="http://schemas.android.com/apk/res/android"
style="@android:style/Widget.Material.Button.Borderless.Small"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/smart_reply_button_spacing"
+ android:layout_height="match_parent"
+ android:minWidth="0dp"
+ android:minHeight="@dimen/smart_reply_button_min_height"
android:paddingVertical="@dimen/smart_reply_button_padding_vertical"
- android:paddingHorizontal="@dimen/smart_reply_button_corner_radius"
android:background="@drawable/smart_reply_button_background"
android:gravity="center"
android:fontFamily="sans-serif"
android:textSize="@dimen/smart_reply_button_font_size"
+ android:lineSpacingExtra="@dimen/smart_reply_button_line_spacing_extra"
android:textColor="@color/smart_reply_button_text"
android:textStyle="normal"
- android:singleLine="true"/> \ No newline at end of file
+ android:ellipsize="none"/> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/smart_reply_view.xml b/packages/SystemUI/res/layout/smart_reply_view.xml
index 6d5338697161..6f21787a1524 100644
--- a/packages/SystemUI/res/layout/smart_reply_view.xml
+++ b/packages/SystemUI/res/layout/smart_reply_view.xml
@@ -19,9 +19,12 @@
<!-- LinearLayout -->
<com.android.systemui.statusbar.policy.SmartReplyView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:id="@+id/smart_reply_view"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
- android:layout_gravity="end">
+ systemui:spacing="@dimen/smart_reply_button_spacing"
+ systemui:singleLineButtonPaddingHorizontal="@dimen/smart_reply_button_padding_horizontal_single_line"
+ systemui:doubleLineButtonPaddingHorizontal="@dimen/smart_reply_button_padding_horizontal_double_line">
<!-- smart_reply_button(s) will be added here. -->
</com.android.systemui.statusbar.policy.SmartReplyView> \ No newline at end of file
diff --git a/packages/SystemUI/res/values/arrays_tv.xml b/packages/SystemUI/res/values/arrays_tv.xml
index 7541b0e8c084..9197bb51e1a6 100644
--- a/packages/SystemUI/res/values/arrays_tv.xml
+++ b/packages/SystemUI/res/values/arrays_tv.xml
@@ -30,7 +30,7 @@
<item>com.google.android.apps.mediashell/.settings.CastSettingsActivity</item>
<item>com.google.android.katniss.setting/.SpeechSettingsActivity</item>
<item>com.google.android.katniss.setting/.SearchSettingsActivity</item>
- <item>com.google.android.gsf.notouch/.UsageDiagnosticsSettingActivity</item>
+ <item>com.google.android.tungsten.setupwraith/.settings.usage.UsageDiagnosticsSettingActivity</item>
<item>com.google.android.tvlauncher/.notifications.NotificationsSidePanelActivity</item>
</string-array>
</resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index a923f0b8c332..f0a5fe421b84 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -130,5 +130,11 @@
<attr name="darkIconTheme" format="reference" />
<attr name="wallpaperTextColor" format="reference|color" />
<attr name="wallpaperTextColorSecondary" format="reference|color" />
+
+ <declare-styleable name="SmartReplyView">
+ <attr name="spacing" format="dimension" />
+ <attr name="singleLineButtonPaddingHorizontal" format="dimension" />
+ <attr name="doubleLineButtonPaddingHorizontal" format="dimension" />
+ </declare-styleable>
</resources>
diff --git a/packages/SystemUI/res/values/attrs_car.xml b/packages/SystemUI/res/values/attrs_car.xml
new file mode 100644
index 000000000000..b1097c39363c
--- /dev/null
+++ b/packages/SystemUI/res/values/attrs_car.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+ <!-- Allow for custom attribs to be added to a facet button -->
+ <declare-styleable name="CarFacetButton">
+ <!-- icon to be rendered (drawable) -->
+ <attr name="icon" format="reference"/>
+ <!-- intent to start when button is click -->
+ <attr name="intent" format="string"/>
+ <!-- intent to start when a long press has happened -->
+ <attr name="longIntent" format="string"/>
+ <!-- categories that will be added as extras to the fired intents -->
+ <attr name="categories" format="string"/>
+ <!-- package names that will be added as extras to the fired intents -->
+ <attr name="packages" format="string" />
+ </declare-styleable>
+
+
+ <!-- Allow for custom attribs to be added to a nav button -->
+ <declare-styleable name="CarNavigationButton">
+ <!-- intent to start when button is click -->
+ <attr name="intent" format="string"/>
+ <!-- intent to start when a long press has happened -->
+ <attr name="longIntent" format="string"/>
+ <!-- start the intent as a broad cast instead of an activity if true-->
+ <attr name="broadcast" format="boolean"/>
+ </declare-styleable>
+</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 4fcfdf7558f9..c054d16644e4 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -156,9 +156,8 @@
<color name="zen_introduction">#ffffffff</color>
-
- <color name="smart_reply_button_text">#ff4285f4</color><!-- blue 500 -->
- <color name="smart_reply_button_background">#fff7f7f7</color>
+ <color name="smart_reply_button_text">#de000000</color> <!-- 87% black -->
+ <color name="smart_reply_button_background">#fff2f2f2</color>
<!-- Fingerprint dialog colors -->
<color name="fingerprint_dialog_bg_color">#f4ffffff</color> <!-- 96% white -->
@@ -166,4 +165,6 @@
<color name="fingerprint_dialog_dim_color">#80000000</color> <!-- 50% black -->
<color name="fingerprint_error_message_color">#ff5722</color>
+ <!-- Logout button -->
+ <color name="logout_button_bg_color">#ccffffff</color>
</resources>
diff --git a/packages/SystemUI/res/values/config_car.xml b/packages/SystemUI/res/values/config_car.xml
index 9c8dcb1b975a..db829f25802e 100644
--- a/packages/SystemUI/res/values/config_car.xml
+++ b/packages/SystemUI/res/values/config_car.xml
@@ -22,4 +22,9 @@
uri that will be launched into the docked window. -->
<bool name="config_enablePersistentDockedActivity">false</bool>
<string name="config_persistentDockedActivityIntentUri" translatable="false"></string>
+
+ <!-- configure which system ui bars should be displayed -->
+ <bool name="config_enableLeftNavigationBar">false</bool>
+ <bool name="config_enableRightNavigationBar">false</bool>
+ <bool name="config_enableBottomNavigationBar">true</bool>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 3f6c85fc67ad..3ff553e156c7 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -230,7 +230,7 @@
<!-- The height of the quick settings footer that holds the user switcher, settings icon,
etc. -->
- <dimen name="qs_footer_height">48dp</dimen>
+ <dimen name="qs_footer_height">56dp</dimen>
<!-- The padding between the notifications and the quick settings container -->
<dimen name="qs_notification_padding">@dimen/notification_side_paddings</dimen>
@@ -337,7 +337,7 @@
<dimen name="qs_footer_padding_end">24dp</dimen>
<dimen name="qs_footer_icon_size">16dp</dimen>
<!-- Difference between drag handle margin in QQS and expanded QS -->
- <dimen name="qs_footer_drag_handle_offset">6dp</dimen>
+ <dimen name="qs_footer_drag_handle_offset">10dp</dimen>
<dimen name="qs_notif_collapsed_space">64dp</dimen>
@@ -513,7 +513,7 @@
<dimen name="multi_user_avatar_keyguard_size">22dp</dimen>
<!-- The width of user avatar when expanded -->
- <dimen name="multi_user_avatar_expanded_size">16dp</dimen>
+ <dimen name="multi_user_avatar_expanded_size">18dp</dimen>
<!-- The font size of the time when collapsed in QS -->
<dimen name="qs_time_collapsed_size">14sp</dimen>
@@ -884,13 +884,16 @@
<dimen name="nav_quick_scrub_track_thickness">2dp</dimen>
<!-- Home button padding for sizing -->
- <dimen name="home_padding">15dp</dimen>
+ <dimen name="home_padding">16dp</dimen>
<!-- Smart reply button -->
- <dimen name="smart_reply_button_corner_radius">24dip</dimen>
<dimen name="smart_reply_button_spacing">8dp</dimen>
- <dimen name="smart_reply_button_padding_vertical">4dp</dimen>
+ <dimen name="smart_reply_button_padding_vertical">10dp</dimen>
+ <dimen name="smart_reply_button_padding_horizontal_single_line">12dp</dimen>
+ <dimen name="smart_reply_button_padding_horizontal_double_line">16dp</dimen>
+ <dimen name="smart_reply_button_min_height">40dp</dimen>
<dimen name="smart_reply_button_font_size">14sp</dimen>
+ <dimen name="smart_reply_button_line_spacing_extra">6sp</dimen> <!-- Total line height 20sp. -->
<dimen name="fingerprint_dialog_icon_size">44dp</dimen>
<dimen name="fingerprint_dialog_fp_icon_size">60dp</dimen>
@@ -920,9 +923,16 @@
<integer name="wireless_charging_fade_duration">200</integer>
<!-- Wired charging on AOD, text animation duration -->
- <integer name="wired_charging_aod_text_animation_duration_down">500</integer>
+ <integer name="wired_charging_keyguard_text_animation_duration_down">500</integer>
<!-- Wired charging on AOD, text animation duration -->
- <integer name="wired_charging_aod_text_animation_duration_up">300</integer>
+ <integer name="wired_charging_keyguard_text_animation_duration_up">300</integer>
<!-- Wired charging on AOD, text animation distance -->
- <integer name="wired_charging_aod_text_animation_distance">-30</integer>
+ <integer name="wired_charging_keyguard_text_animation_distance">-30</integer>
+
+ <!-- Logout button -->
+ <dimen name="logout_button_layout_height">32dp</dimen>
+ <dimen name="logout_button_padding_horizontal">16dp</dimen>
+ <dimen name="logout_button_margin_bottom">12dp</dimen>
+ <dimen name="logout_button_corner_radius">2dp</dimen>
+
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index dc082a99d53e..8c59e75315a1 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1751,15 +1751,13 @@
<string-array name="nav_bar_buttons">
<item>Clipboard</item>
<item>Keycode</item>
- <item>Keyboard switcher</item>
- <item>Rotation suggestion</item>
+ <item>Rotate confirm, keyboard switcher</item>
<item>None</item>
</string-array>
<string-array name="nav_bar_button_values" translatable="false">
<item>clipboard</item>
<item>key</item>
<item>menu_ime</item>
- <item>rotate</item>
<item>space</item>
</string-array>
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 7f382acb0aab..e200a7fee4e6 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
@@ -23,6 +23,14 @@ oneway interface IOverviewProxy {
void onBind(in ISystemUiProxy sysUiProxy);
/**
+ * 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
+ */
+ void onPreMotionEvent(int downHitTarget);
+
+ /**
* Proxies motion events from the nav bar in SystemUI to the OverviewProxyService. The sender
* guarantees the following order of events:
*
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 4cf817e02fff..b8319a8e8822 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -44,4 +44,9 @@ interface ISystemUiProxy {
* Specifies the text to be shown for onboarding the new swipe-up gesture to access recents.
*/
void setRecentsOnboardingText(CharSequence text);
+
+ /**
+ * Enables/disables launcher/overview interaction features {@link InteractionType}.
+ */
+ void setInteractionState(int flags);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 62bd72f393cc..138910cb9820 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -316,6 +316,17 @@ public class ActivityManagerWrapper {
}
/**
+ * Cancels the remote recents animation started from {@link #startRecentsActivity}.
+ */
+ public void cancelRecentsAnimation() {
+ try {
+ ActivityManager.getService().cancelRecentsAnimation();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to cancel recents animation", e);
+ }
+ }
+
+ /**
* Starts a task from Recents.
*
* @see {@link #startActivityFromRecentsAsync(TaskKey, ActivityOptions, int, int, Consumer, Handler)}
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
new file mode 100644
index 000000000000..171918682099
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
@@ -0,0 +1,60 @@
+/*
+ * 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
+ */
+
+package com.android.systemui.shared.system;
+
+import android.annotation.IntDef;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+public class NavigationBarCompat {
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({HIT_TARGET_NONE, HIT_TARGET_BACK, HIT_TARGET_HOME})
+ public @interface HitTarget{}
+
+ public static final int HIT_TARGET_NONE = 0;
+ public static final int HIT_TARGET_BACK = 1;
+ public static final int HIT_TARGET_HOME = 2;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({FLAG_DISABLE_SWIPE_UP,
+ FLAG_DISABLE_QUICK_SCRUB,
+ FLAG_SHOW_OVERVIEW_BUTTON,
+ FLAG_HIDE_BACK_BUTTON
+ })
+ public @interface InteractionType {}
+
+ /**
+ * Interaction type: whether the gesture to swipe up from the navigation bar will trigger
+ * launcher to show overview
+ */
+
+ public static final int FLAG_DISABLE_SWIPE_UP = 0x1;
+ /**
+ * Interaction type: enable quick scrub and switch interaction on the home button
+ */
+ public static final int FLAG_DISABLE_QUICK_SCRUB = 0x2;
+
+ /**
+ * Interaction type: show/hide the overview button while this service is connected to launcher
+ */
+ public static final int FLAG_SHOW_OVERVIEW_BUTTON = 0x4;
+
+ /**
+ * Interaction type: show/hide the back button while this service is connected to launcher
+ */
+ public static final int FLAG_HIDE_BACK_BUTTON = 0x8;
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index e440731dcd47..3b5f34cd84cc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -16,13 +16,16 @@
package com.android.keyguard;
+import android.app.ActivityManager;
import android.app.AlarmManager;
+import android.app.IActivityManager;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Handler;
import android.os.Looper;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.support.v4.graphics.ColorUtils;
import android.text.TextUtils;
@@ -51,9 +54,11 @@ public class KeyguardStatusView extends GridLayout {
private final LockPatternUtils mLockPatternUtils;
private final AlarmManager mAlarmManager;
+ private final IActivityManager mIActivityManager;
private final float mSmallClockScale;
private final float mWidgetPadding;
+ private TextView mLogoutView;
private TextClock mClockView;
private View mClockSeparator;
private TextView mOwnerInfo;
@@ -80,6 +85,7 @@ public class KeyguardStatusView extends GridLayout {
if (DEBUG) Slog.v(TAG, "refresh statusview showing:" + showing);
refresh();
updateOwnerInfo();
+ updateLogoutView();
}
}
@@ -97,6 +103,12 @@ public class KeyguardStatusView extends GridLayout {
public void onUserSwitchComplete(int userId) {
refresh();
updateOwnerInfo();
+ updateLogoutView();
+ }
+
+ @Override
+ public void onLogoutEnabledChanged() {
+ updateLogoutView();
}
};
@@ -111,6 +123,7 @@ public class KeyguardStatusView extends GridLayout {
public KeyguardStatusView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ mIActivityManager = ActivityManager.getService();
mLockPatternUtils = new LockPatternUtils(getContext());
mHandler = new Handler(Looper.myLooper());
mSmallClockScale = getResources().getDimension(R.dimen.widget_small_font_size)
@@ -145,6 +158,9 @@ public class KeyguardStatusView extends GridLayout {
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mLogoutView = findViewById(R.id.logout);
+ mLogoutView.setOnClickListener(this::onLogoutClicked);
+
mClockContainer = findViewById(R.id.keyguard_clock_container);
mClockView = findViewById(R.id.clock_view);
mClockView.setShowCurrentUserTime(true);
@@ -164,6 +180,7 @@ public class KeyguardStatusView extends GridLayout {
setEnableMarquee(shouldMarquee);
refresh();
updateOwnerInfo();
+ updateLogoutView();
// Disable elegant text height because our fancy colon makes the ymin value huge for no
// reason.
@@ -213,14 +230,28 @@ public class KeyguardStatusView extends GridLayout {
}
public int getClockBottom() {
- return mKeyguardSlice.getVisibility() == VISIBLE ? mKeyguardSlice.getBottom()
- : mClockView.getBottom();
+ if (mOwnerInfo != null && mOwnerInfo.getVisibility() == VISIBLE) {
+ return mOwnerInfo.getBottom();
+ } else {
+ return mClockContainer.getBottom();
+ }
+ }
+
+ public int getLogoutButtonHeight() {
+ return mLogoutView.getVisibility() == VISIBLE ? mLogoutView.getHeight() : 0;
}
public float getClockTextSize() {
return mClockView.getTextSize();
}
+ private void updateLogoutView() {
+ mLogoutView.setVisibility(shouldShowLogout() ? VISIBLE : GONE);
+ // Logout button will stay in language of user 0 if we don't set that manually.
+ mLogoutView.setText(mContext.getResources().getString(
+ com.android.internal.R.string.global_action_logout));
+ }
+
private void updateOwnerInfo() {
if (mOwnerInfo == null) return;
String ownerInfo = getOwnerInfo();
@@ -309,6 +340,7 @@ public class KeyguardStatusView extends GridLayout {
mDarkAmount = darkAmount;
boolean dark = darkAmount == 1;
+ mLogoutView.setAlpha(dark ? 0 : 1);
final int N = mClockContainer.getChildCount();
for (int i = 0; i < N; i++) {
View child = mClockContainer.getChildAt(i);
@@ -340,4 +372,19 @@ public class KeyguardStatusView extends GridLayout {
child.setAlpha(mDarkAmount == 1 && mPulsing ? 0.8f : 1);
}
}
+
+ private boolean shouldShowLogout() {
+ return KeyguardUpdateMonitor.getInstance(mContext).isLogoutEnabled()
+ && KeyguardUpdateMonitor.getCurrentUser() != UserHandle.USER_SYSTEM;
+ }
+
+ private void onLogoutClicked(View view) {
+ int currentUserId = KeyguardUpdateMonitor.getCurrentUser();
+ try {
+ mIActivityManager.switchUser(UserHandle.USER_SYSTEM);
+ mIActivityManager.stopUser(currentUserId, true /*force*/, null);
+ } catch (RemoteException re) {
+ Log.e(TAG, "Failed to logout user", re);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 9e4b4055a289..f3f8d91f794b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -141,6 +141,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
private static final int MSG_USER_UNLOCKED = 334;
private static final int MSG_ASSISTANT_STACK_CHANGED = 335;
private static final int MSG_FINGERPRINT_AUTHENTICATION_CONTINUE = 336;
+ private static final int MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED = 337;
/** Fingerprint state: Not listening to fingerprint. */
private static final int FINGERPRINT_STATE_STOPPED = 0;
@@ -225,6 +226,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
private LockPatternUtils mLockPatternUtils;
private final IDreamManager mDreamManager;
private boolean mIsDreaming;
+ private final DevicePolicyManager mDevicePolicyManager;
+ private boolean mLogoutEnabled;
/**
* Short delay before restarting fingerprint authentication after a successful try
@@ -330,6 +333,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
case MSG_FINGERPRINT_AUTHENTICATION_CONTINUE:
updateFingerprintListeningState();
break;
+ case MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED:
+ updateLogoutEnabled();
+ break;
}
}
};
@@ -795,6 +801,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
mHandler.sendMessage(
mHandler.obtainMessage(MSG_SERVICE_STATE_CHANGE, subId, 0, serviceState));
+ } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(
+ action)) {
+ mHandler.sendEmptyMessage(MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED);
}
}
};
@@ -1159,6 +1168,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
+ filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
context.registerReceiver(mBroadcastReceiver, filter);
final IntentFilter bootCompleteFilter = new IntentFilter();
@@ -1213,6 +1223,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
mUserManager = context.getSystemService(UserManager.class);
+ mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class);
+ mLogoutEnabled = mDevicePolicyManager.isLogoutEnabled();
}
private void updateFingerprintListeningState() {
@@ -1936,6 +1948,26 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
return null; // not found
}
+ /**
+ * @return a cached version of DevicePolicyManager.isLogoutEnabled()
+ */
+ public boolean isLogoutEnabled() {
+ return mLogoutEnabled;
+ }
+
+ private void updateLogoutEnabled() {
+ boolean logoutEnabled = mDevicePolicyManager.isLogoutEnabled();
+ if (mLogoutEnabled != logoutEnabled) {
+ mLogoutEnabled = logoutEnabled;
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onLogoutEnabledChanged();
+ }
+ }
+ }
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("KeyguardUpdateMonitor state:");
pw.println(" SIM States:");
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 1afcca64de69..67571bb2ab38 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -283,4 +283,11 @@ public class KeyguardUpdateMonitorCallback {
* @see KeyguardIndicationController#showTransientIndication(CharSequence)
*/
public void onTrustAgentErrorMessage(CharSequence message) { }
+
+
+ /**
+ * Called when a value of logout enabled is change.
+ */
+ public void onLogoutEnabledChanged() { }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index d0128efe2c44..1185f45469df 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -47,6 +47,8 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
+
/**
* Class to send information from overview to launcher with a binder.
*/
@@ -67,6 +69,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
private IOverviewProxy mOverviewProxy;
private int mConnectionBackoffAttempts;
private CharSequence mOnboardingText;
+ private @InteractionType int mInteractionFlags;
private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
@@ -108,6 +111,22 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
public void setRecentsOnboardingText(CharSequence text) {
mOnboardingText = text;
}
+
+ public void setInteractionState(@InteractionType int flags) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ if (mInteractionFlags != flags) {
+ mInteractionFlags = flags;
+ mHandler.post(() -> {
+ for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
+ mConnectionCallbacks.get(i).onInteractionFlagsChanged(flags);
+ }
+ });
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
};
private final BroadcastReceiver mLauncherAddedReceiver = new BroadcastReceiver() {
@@ -230,6 +249,10 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
return mOnboardingText;
}
+ public int getInteractionFlags() {
+ return mInteractionFlags;
+ }
+
private void disconnectFromLauncherService() {
if (mOverviewProxy != null) {
mOverviewProxy.asBinder().unlinkToDeath(mOverviewServiceDeathRcpt, 0);
@@ -263,5 +286,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
public interface OverviewProxyListener {
default void onConnectionChanged(boolean isConnected) {}
default void onRecentsAnimationStarted() {}
+ default void onInteractionFlagsChanged(@InteractionType int flags) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index ddf0bd0cbab4..bb82a54c12f1 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -28,6 +28,8 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import com.android.internal.os.BinderInternal;
+import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.plugins.PluginManagerImpl;
public class SystemUIService extends Service {
@@ -70,6 +72,10 @@ public class SystemUIService extends Service {
pw.println("dumping service: " + ui.getClass().getName());
ui.dump(fd, pw, args);
}
+ if (Build.IS_DEBUGGABLE) {
+ pw.println("dumping plugins:");
+ ((PluginManagerImpl) Dependency.get(PluginManager.class)).dump(fd, pw, args);
+ }
} else {
String svc = args[0];
for (SystemUI ui: services) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 34d392861d7c..aa264190f800 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -59,6 +59,12 @@ public class DozeService extends DreamService
}
@Override
+ public void onDestroy() {
+ Dependency.get(PluginManager.class).removePluginListener(this);
+ super.onDestroy();
+ }
+
+ @Override
public void onPluginConnected(DozeServicePlugin plugin, Context pluginContext) {
mDozePlugin = plugin;
mDozePlugin.setDozeRequester(this);
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index c28b7eed1614..259bff28d458 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -688,7 +688,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
private Action getLockdownAction() {
- return new SinglePressAction(R.drawable.ic_lock_lock,
+ return new SinglePressAction(com.android.systemui.R.drawable.ic_lock_lockdown,
R.string.global_action_lockdown) {
@Override
@@ -1369,6 +1369,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mListView = findViewById(android.R.id.list);
mHardwareLayout = HardwareUiLayout.get(mListView);
mHardwareLayout.setOutsideTouchListener(view -> dismiss());
+ setTitle(R.string.global_actions);
}
private void updateList() {
@@ -1464,20 +1465,6 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
@Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
- for (int i = 0; i < mAdapter.getCount(); ++i) {
- CharSequence label =
- mAdapter.getItem(i).getLabelForAccessibility(getContext());
- if (label != null) {
- event.getText().add(label);
- }
- }
- }
- return super.dispatchPopulateAccessibilityEvent(event);
- }
-
- @Override
public void onColorsChanged(ColorExtractor extractor, int which) {
if (mKeyguardShowing) {
if ((WallpaperManager.FLAG_LOCK & which) != 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
index 82c0128c10c0..d5541e9be17e 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -168,6 +168,12 @@ public class PluginInstanceManager<T extends Plugin> {
return false;
}
+ @Override
+ public String toString() {
+ return String.format("%s@%s (action=%s)",
+ getClass().getSimpleName(), hashCode(), mAction);
+ }
+
private class MainHandler extends Handler {
private static final int PLUGIN_CONNECTED = 1;
private static final int PLUGIN_DISCONNECTED = 2;
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
index 03747d50a6fa..2a17e35f00dd 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
@@ -50,6 +50,8 @@ import com.android.systemui.plugins.annotations.ProvidesInterface;
import dalvik.system.PathClassLoader;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Map;
@@ -303,6 +305,14 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
}
}
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println(String.format(" plugin map (%d):", mPluginMap.size()));
+ for (PluginListener listener: mPluginMap.keySet()) {
+ pw.println(String.format(" %s -> %s",
+ listener, mPluginMap.get(listener)));
+ }
+ }
+
@VisibleForTesting
public static class PluginInstanceManagerFactory {
public <T extends Plugin> PluginInstanceManager createPluginInstanceManager(Context context,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index fe3ffb926305..e24135775e79 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -174,7 +174,9 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
.addFloat(mDivider, "alpha", 0, 1)
.addFloat(mCarrierText, "alpha", 0, 1)
.addFloat(mActionsContainer, "alpha", 0, 1)
- .addFloat(mDragHandle, "translationY", 0, -mDragHandleExpandOffset)
+ .addFloat(mDragHandle, "translationY", mDragHandleExpandOffset, 0)
+ .addFloat(mDragHandle, "alpha", 1, 0)
+ .setStartDelay(0.15f)
.build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 7fe9e3584ee5..2a9a3818a746 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -78,6 +78,7 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
@Override
public void handleSetListening(boolean listening) {
+ if (mController == null) return;
if (listening) {
mController.addCallback(mCallback);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 6205e9afcb03..2d31669db6c2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -240,6 +240,7 @@ public class DndTile extends QSTileImpl<BooleanState> {
public void handleSetListening(boolean listening) {
if (mListening == listening) return;
mListening = listening;
+ if (mController == null) return;
if (mListening) {
mController.addCallback(mZenCallback);
Prefs.registerListener(mContext, mPrefListener);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
index b3ff4e5b890c..12daff1f12f9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
@@ -98,6 +98,8 @@ public class NfcTile extends QSTileImpl<BooleanState> {
protected void handleUpdateState(BooleanState state, Object arg) {
final Drawable mEnable = mContext.getDrawable(R.drawable.ic_qs_nfc_enabled);
final Drawable mDisable = mContext.getDrawable(R.drawable.ic_qs_nfc_disabled);
+
+ if (getAdapter() == null) return;
state.value = getAdapter().isEnabled();
state.label = mContext.getString(R.string.quick_settings_nfc_label);
state.icon = new DrawableIcon(state.value ? mEnable : mDisable);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 57f7818eae58..3dd6e353c924 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -36,6 +36,7 @@ import android.view.accessibility.AccessibilityManager;
import android.view.animation.DecelerateInterpolator;
import android.widget.Button;
import android.widget.FrameLayout;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -255,6 +256,11 @@ public class ScreenPinningRequest implements View.OnClickListener {
: R.string.screen_pinning_description_recents_invisible;
}
+ ((ImageView) mLayout.findViewById(R.id.screen_pinning_back_icon))
+ .setImageDrawable(navigationBarView.getBackDrawable(mContext));
+ ((ImageView) mLayout.findViewById(R.id.screen_pinning_home_icon))
+ .setImageDrawable(navigationBarView.getHomeDrawable(mContext));
+
((TextView) mLayout.findViewById(R.id.screen_pinning_description))
.setText(descriptionStringResId);
final int backBgVisibility = touchExplorationEnabled ? View.INVISIBLE : View.VISIBLE;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index bf4a225a00ec..2acb1bb2613b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -38,10 +38,12 @@ import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
+import android.graphics.Picture;
import android.graphics.PixelFormat;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -57,13 +59,10 @@ import android.provider.MediaStore;
import android.util.DisplayMetrics;
import android.util.Slog;
import android.view.Display;
-import android.view.DisplayListCanvas;
import android.view.LayoutInflater;
import android.view.MotionEvent;
-import android.view.RenderNode;
import android.view.Surface;
import android.view.SurfaceControl;
-import android.view.ThreadedRenderer;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
@@ -233,14 +232,12 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
*/
private Bitmap generateAdjustedHwBitmap(Bitmap bitmap, int width, int height, Matrix matrix,
Paint paint, int color) {
- RenderNode node = RenderNode.create("ScreenshotCanvas", null);
- node.setLeftTopRightBottom(0, 0, width, height);
- node.setClipToBounds(false);
- DisplayListCanvas canvas = node.start(width, height);
+ Picture picture = new Picture();
+ Canvas canvas = picture.beginRecording(width, height);
canvas.drawColor(color);
canvas.drawBitmap(bitmap, matrix, paint);
- node.end(canvas);
- return ThreadedRenderer.createHardwareBitmap(node, width, height);
+ picture.endRecording();
+ return Bitmap.createBitmap(picture);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index eb5619b11487..0876507465a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -308,6 +308,10 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
}
}
+ public void setRippleAllowed(boolean allowed) {
+ mBackgroundNormal.setPressedAllowed(allowed);
+ }
+
private boolean handleTouchEventDimmed(MotionEvent event) {
if (mNeedsDimming && !mDimmed) {
// We're actually dimmed, but our content isn't dimmable, let's ensure we have a ripple
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index b3f68d357083..2723df73aa52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -370,14 +370,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mNotificationInflater.inflateNotificationViews();
}
- @Override
- public void setPressed(boolean pressed) {
- if (isOnKeyguard() || mEntry.notification.getNotification().contentIntent == null) {
- // We're dropping the ripple if we have a collapse / launch animation
- super.setPressed(pressed);
- }
- }
-
public void onNotificationUpdated() {
for (NotificationContentView l : mLayouts) {
l.onNotificationUpdated(mEntry);
@@ -407,6 +399,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
showBlockingHelper(mEntry.userSentiment ==
NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE);
+ updateRippleAllowed();
}
@VisibleForTesting
@@ -1805,6 +1798,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
}
}
+ updateRippleAllowed();
+ }
+
+ private void updateRippleAllowed() {
+ boolean allowed = isOnKeyguard()
+ || mEntry.notification.getNotification().contentIntent == null;
+ setRippleAllowed(allowed);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index b7a15005b170..22e8909b4812 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -300,34 +300,10 @@ public class KeyguardIndicationController {
} else if (mPowerPluggedIn) {
String indication = computePowerIndication();
if (animate) {
- int yTranslation = mContext.getResources().getInteger(
- R.integer.wired_charging_aod_text_animation_distance);
- int animateUpDuration = mContext.getResources().getInteger(
- R.integer.wired_charging_aod_text_animation_duration_up);
- int animateDownDuration = mContext.getResources().getInteger(
- R.integer.wired_charging_aod_text_animation_duration_down);
- mTextView.animate()
- .translationYBy(yTranslation)
- .setInterpolator(Interpolators.LINEAR)
- .setDuration(animateUpDuration)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mTextView.switchIndication(indication);
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- mTextView.animate()
- .setDuration(animateDownDuration)
- .setInterpolator(Interpolators.BOUNCE)
- .translationYBy(-1 * yTranslation)
- .setListener(null);
- }
- });
+ animateText(mTextView, indication);
} else {
mTextView.switchIndication(indication);
}
-
} else {
String percentage = NumberFormat.getPercentInstance()
.format(mBatteryLevel / 100f);
@@ -355,8 +331,12 @@ public class KeyguardIndicationController {
if (DEBUG_CHARGING_SPEED) {
indication += ", " + (mChargingWattage / 1000) + " mW";
}
- mTextView.switchIndication(indication);
mTextView.setTextColor(mInitialTextColor);
+ if (animate) {
+ animateText(mTextView, indication);
+ } else {
+ mTextView.switchIndication(indication);
+ }
} else if (!TextUtils.isEmpty(trustManagedIndication)
&& updateMonitor.getUserTrustIsManaged(userId)
&& !updateMonitor.getUserHasTrust(userId)) {
@@ -369,6 +349,34 @@ public class KeyguardIndicationController {
}
}
+ // animates textView - textView moves up and bounces down
+ private void animateText(KeyguardIndicationTextView textView, String indication) {
+ int yTranslation = mContext.getResources().getInteger(
+ R.integer.wired_charging_keyguard_text_animation_distance);
+ int animateUpDuration = mContext.getResources().getInteger(
+ R.integer.wired_charging_keyguard_text_animation_duration_up);
+ int animateDownDuration = mContext.getResources().getInteger(
+ R.integer.wired_charging_keyguard_text_animation_duration_down);
+ textView.animate()
+ .translationYBy(yTranslation)
+ .setInterpolator(Interpolators.LINEAR)
+ .setDuration(animateUpDuration)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ textView.switchIndication(indication);
+ }
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ textView.animate()
+ .setDuration(animateDownDuration)
+ .setInterpolator(Interpolators.BOUNCE)
+ .translationYBy(-1 * yTranslation)
+ .setListener(null);
+ }
+ });
+ }
+
private String computePowerIndication() {
if (mPowerCharged) {
return mContext.getResources().getString(R.string.keyguard_charged);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
index ab89a5287cdb..0ff4dde580b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -28,6 +28,7 @@ import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
import android.view.View;
+import com.android.internal.util.ArrayUtils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
@@ -50,6 +51,7 @@ public class NotificationBackgroundView extends View {
private boolean mExpandAnimationRunning;
private float mActualWidth;
private int mDrawableAlpha = 255;
+ private boolean mIsPressedAllowed;
public NotificationBackgroundView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -94,13 +96,7 @@ public class NotificationBackgroundView extends View {
@Override
protected void drawableStateChanged() {
- drawableStateChanged(mBackground);
- }
-
- private void drawableStateChanged(Drawable d) {
- if (d != null && d.isStateful()) {
- d.setState(getDrawableState());
- }
+ setState(getDrawableState());
}
@Override
@@ -177,7 +173,13 @@ public class NotificationBackgroundView extends View {
}
public void setState(int[] drawableState) {
- mBackground.setState(drawableState);
+ if (mBackground != null && mBackground.isStateful()) {
+ if (!mIsPressedAllowed) {
+ drawableState = ArrayUtils.removeInt(drawableState,
+ com.android.internal.R.attr.state_pressed);
+ }
+ mBackground.setState(drawableState);
+ }
}
public void setRippleColor(int color) {
@@ -258,4 +260,8 @@ public class NotificationBackgroundView extends View {
}
invalidate();
}
+
+ public void setPressedAllowed(boolean allowed) {
+ mIsPressedAllowed = allowed;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
index 1aaa3b2593d2..f730601ac919 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
@@ -24,6 +24,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.net.Uri;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -131,12 +132,13 @@ public class NotificationGutsManager implements Dumpable {
}
/**
- * Sends an intent to open the notification settings for a particular package and optional
+ * Sends an intent to open the app settings for a particular package and optional
* channel.
*/
private void startAppNotificationSettingsActivity(String packageName, final int appUid,
final NotificationChannel channel, ExpandableNotificationRow row) {
- final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
+ final Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ intent.setData(Uri.fromParts("package", packageName, null));
intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
intent.putExtra(Settings.EXTRA_APP_UID, appUid);
if (channel != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
new file mode 100644
index 000000000000..53101a5bd61f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
@@ -0,0 +1,161 @@
+package com.android.systemui.statusbar.car;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+
+import com.android.keyguard.AlphaOptimizedImageButton;
+import com.android.systemui.R;
+
+/**
+ * CarFacetButton is a ui component designed to be used as a shortcut for an app of a defined
+ * category. It can also render a indicator impling that there are more options of apps to launch
+ * using this component. This is done with a "More icon" currently an arrow as defined in the layout
+ * file. The class is to serve as an example.
+ * Usage example: A button that allows a user to select a music app and indicate that there are
+ * other music apps installed.
+ */
+public class CarFacetButton extends LinearLayout {
+ private static final float SELECTED_ALPHA = 1f;
+ private static final float UNSELECTED_ALPHA = 0.7f;
+
+ private static final String FACET_FILTER_DELIMITER = ";";
+ /**
+ * Extra information to be sent to a helper to make the decision of what app to launch when
+ * clicked.
+ */
+ private static final String EXTRA_FACET_CATEGORIES = "categories";
+ private static final String EXTRA_FACET_PACKAGES = "packages";
+ private static final String EXTRA_FACET_ID = "filter_id";
+ private static final String EXTRA_FACET_LAUNCH_PICKER = "launch_picker";
+
+ private Context mContext;
+ private AlphaOptimizedImageButton mIcon;
+ private AlphaOptimizedImageButton mMoreIcon;
+ private boolean mSelected = false;
+ /** App categories that are to be used with this widget */
+ private String[] mFacetCategories;
+ /** App packages that are allowed to be used with this widget */
+ private String[] mFacetPackages;
+
+
+ public CarFacetButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mContext = context;
+ View.inflate(context, R.layout.car_facet_button, this);
+
+ // extract custom attributes
+ TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CarFacetButton);
+ setupIntents(typedArray);
+ setupIcons(typedArray);
+ }
+
+ /**
+ * Reads the custom attributes to setup click handlers for this component.
+ */
+ private void setupIntents(TypedArray typedArray) {
+ String intentString = typedArray.getString(R.styleable.CarFacetButton_intent);
+ String longPressIntentString = typedArray.getString(R.styleable.CarFacetButton_longIntent);
+ String categoryString = typedArray.getString(R.styleable.CarFacetButton_categories);
+ String packageString = typedArray.getString(R.styleable.CarFacetButton_packages);
+ try {
+ final Intent intent = Intent.parseUri(intentString, Intent.URI_INTENT_SCHEME);
+ intent.putExtra(EXTRA_FACET_ID, Integer.toString(getId()));
+
+ if (packageString != null) {
+ mFacetPackages = packageString.split(FACET_FILTER_DELIMITER);
+ intent.putExtra(EXTRA_FACET_PACKAGES, mFacetPackages);
+ }
+ if (categoryString != null) {
+ mFacetCategories = categoryString.split(FACET_FILTER_DELIMITER);
+ intent.putExtra(EXTRA_FACET_CATEGORIES, mFacetCategories);
+ }
+
+ setOnClickListener(v -> {
+ intent.putExtra(EXTRA_FACET_LAUNCH_PICKER, mSelected);
+ mContext.startActivity(intent);
+ });
+
+ if (longPressIntentString != null) {
+ final Intent longPressIntent = Intent.parseUri(longPressIntentString,
+ Intent.URI_INTENT_SCHEME);
+ setOnLongClickListener(v -> {
+ mContext.startActivity(longPressIntent);
+ return true;
+ });
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to attach intent", e);
+ }
+ }
+
+
+ private void setupIcons(TypedArray styledAttributes) {
+ mIcon = findViewById(R.id.car_nav_button_icon);
+ mIcon.setScaleType(ImageView.ScaleType.CENTER);
+ mIcon.setClickable(false);
+ mIcon.setAlpha(UNSELECTED_ALPHA);
+ int iconResourceId = styledAttributes.getResourceId(R.styleable.CarFacetButton_icon, 0);
+ if (iconResourceId == 0) {
+ throw new RuntimeException("specified icon resource was not found and is required");
+ }
+ mIcon.setImageResource(iconResourceId);
+
+ mMoreIcon = findViewById(R.id.car_nav_button_more_icon);
+ mMoreIcon.setClickable(false);
+ mMoreIcon.setImageDrawable(getContext().getDrawable(R.drawable.car_ic_arrow));
+ mMoreIcon.setAlpha(UNSELECTED_ALPHA);
+ mMoreIcon.setVisibility(GONE);
+ }
+
+ /**
+ * @return The app categories the component represents
+ */
+ public String[] getCategories() {
+ if (mFacetCategories == null) {
+ return new String[0];
+ }
+ return mFacetCategories;
+ }
+
+ /**
+ * @return The valid packages that should be considered.
+ */
+ public String[] getFacetPackages() {
+ if (mFacetPackages == null) {
+ return new String[0];
+ }
+ return mFacetPackages;
+ }
+
+ /**
+ * Updates the alpha of the icons to "selected" and shows the "More icon"
+ * @param selected true if the view must be selected, false otherwise
+ */
+ public void setSelected(boolean selected) {
+ super.setSelected(selected);
+ setSelected(selected, selected);
+ }
+
+ /**
+ * Updates the visual state to let the user know if it's been selected.
+ * @param selected true if should update the alpha of the icon to selected, false otherwise
+ * @param showMoreIcon true if the "more icon" should be shown, false otherwise
+ */
+ public void setSelected(boolean selected, boolean showMoreIcon) {
+ mSelected = selected;
+ if (selected) {
+ mMoreIcon.setVisibility(showMoreIcon ? VISIBLE : GONE);
+ mMoreIcon.setAlpha(SELECTED_ALPHA);
+ mIcon.setAlpha(SELECTED_ALPHA);
+ } else {
+ mMoreIcon.setVisibility(GONE);
+ mIcon.setAlpha(UNSELECTED_ALPHA);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java
new file mode 100644
index 000000000000..e8c9a5e5693a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java
@@ -0,0 +1,114 @@
+package com.android.systemui.statusbar.car;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * CarFacetButtons placed on the nav bar are designed to have visual indication that the active
+ * application on screen is associated with it. This is basically a similar concept to a radio
+ * button group.
+ */
+public class CarFacetButtonController {
+
+ protected HashMap<String, CarFacetButton> mButtonsByCategory = new HashMap<>();
+ protected HashMap<String, CarFacetButton> mButtonsByPackage = new HashMap<>();
+ protected CarFacetButton mSelectedFacetButton;
+ protected Context mContext;
+
+ public CarFacetButtonController(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Goes through the supplied CarNavigationBarView and keeps track of all the CarFacetButtons
+ * such that it can select and unselect them based on running task chages
+ * @param bar that may contain CarFacetButtons
+ */
+ public void addCarNavigationBar(CarNavigationBarView bar) {
+ findFacets(bar);
+ }
+
+ private void findFacets(ViewGroup root) {
+ final int childCount = root.getChildCount();
+
+ for (int i = 0; i < childCount; ++i) {
+ final View v = root.getChildAt(i);
+ if (v instanceof CarFacetButton) {
+ CarFacetButton facetButton = (CarFacetButton) v;
+ String[] categories = facetButton.getCategories();
+ for (int j = 0; j < categories.length; j++) {
+ String category = categories[j];
+ mButtonsByCategory.put(category, facetButton);
+ }
+
+ String[] facetPackages = facetButton.getFacetPackages();
+ for (int j = 0; j < facetPackages.length; j++) {
+ String facetPackage = facetPackages[j];
+ mButtonsByPackage.put(facetPackage, facetButton);
+ }
+ } else if (v instanceof ViewGroup) {
+ findFacets((ViewGroup) v);
+ }
+ }
+ }
+
+
+ /**
+ * This will unselect the currently selected CarFacetButton and determine which one should be
+ * selected next. It does this by reading the properties on the CarFacetButton and seeing if
+ * they are a match with the supplied taskino.
+ * @param taskInfo of the currently running application
+ */
+ public void taskChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ if (taskInfo == null || taskInfo.baseActivity == null) {
+ return;
+ }
+ String packageName = taskInfo.baseActivity.getPackageName();
+
+ // If the package name belongs to a filter, then highlight appropriate button in
+ // the navigation bar.
+ if (mSelectedFacetButton != null) {
+ mSelectedFacetButton.setSelected(false);
+ }
+ CarFacetButton facetButton = mButtonsByPackage.get(packageName);
+ if (facetButton != null) {
+ facetButton.setSelected(true);
+ mSelectedFacetButton = facetButton;
+ } else {
+ String category = getPackageCategory(packageName);
+ if (category != null) {
+ facetButton = mButtonsByCategory.get(category);
+ facetButton.setSelected(true);
+ mSelectedFacetButton = facetButton;
+ }
+ }
+ }
+
+ protected String getPackageCategory(String packageName) {
+ PackageManager pm = mContext.getPackageManager();
+ Set<String> supportedCategories = mButtonsByCategory.keySet();
+ for (String category : supportedCategories) {
+ Intent intent = new Intent();
+ intent.setPackage(packageName);
+ intent.setAction(Intent.ACTION_MAIN);
+ intent.addCategory(category);
+ List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
+ if (list.size() > 0) {
+ // Cache this package name into facetPackageMap, so we won't have to query
+ // all categories next time this package name shows up.
+ mButtonsByPackage.put(packageName, mButtonsByCategory.get(category));
+ return category;
+ }
+ }
+ return null;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
deleted file mode 100644
index 64c52ed6d29f..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.statusbar.car;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
-import android.support.v4.util.SimpleArrayMap;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.SparseBooleanArray;
-import android.view.View;
-import android.widget.LinearLayout;
-import com.android.systemui.R;
-
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A controller to populate data for CarNavigationBarView and handle user interactions.
- *
- * <p>Each button inside the navigation bar is defined by data in arrays_car.xml. OEMs can
- * customize the navigation buttons by updating arrays_car.xml appropriately in an overlay.
- */
-class CarNavigationBarController {
- private static final String TAG = "CarNavBarController";
-
- private static final String EXTRA_FACET_CATEGORIES = "categories";
- private static final String EXTRA_FACET_PACKAGES = "packages";
- private static final String EXTRA_FACET_ID = "filter_id";
- private static final String EXTRA_FACET_LAUNCH_PICKER = "launch_picker";
-
- /**
- * Each facet of the navigation bar maps to a set of package names or categories defined in
- * arrays_car.xml. Package names for a given facet are delimited by ";".
- */
- private static final String FACET_FILTER_DELIMITER = ";";
-
- private final Context mContext;
- private final CarNavigationBarView mNavBar;
- private final CarStatusBar mStatusBar;
-
- /**
- * Set of categories each facet will filter on.
- */
- private final List<String[]> mFacetCategories = new ArrayList<>();
-
- /**
- * Set of package names each facet will filter on.
- */
- private final List<String[]> mFacetPackages = new ArrayList<>();
-
- private final SimpleArrayMap<String, Integer> mFacetCategoryMap = new SimpleArrayMap<>();
- private final SimpleArrayMap<String, Integer> mFacetPackageMap = new SimpleArrayMap<>();
-
- private final List<CarNavigationButton> mNavButtons = new ArrayList<>();
-
- private final SparseBooleanArray mFacetHasMultipleAppsCache = new SparseBooleanArray();
-
- private int mCurrentFacetIndex;
- private Intent mPersistentTaskIntent;
-
- public CarNavigationBarController(Context context, CarNavigationBarView navBar,
- CarStatusBar activityStarter) {
- mContext = context;
- mNavBar = navBar;
- mStatusBar = activityStarter;
- bind();
-
- if (context.getResources().getBoolean(R.bool.config_enablePersistentDockedActivity)) {
- setupPersistentDockedTask();
- }
- }
-
- private void setupPersistentDockedTask() {
- try {
- mPersistentTaskIntent = Intent.parseUri(
- mContext.getString(R.string.config_persistentDockedActivityIntentUri),
- Intent.URI_INTENT_SCHEME);
- } catch (URISyntaxException e) {
- Log.e(TAG, "Malformed persistent task intent.");
- }
- }
-
- public void taskChanged(String packageName, ActivityManager.RunningTaskInfo taskInfo) {
- // If the package name belongs to a filter, then highlight appropriate button in
- // the navigation bar.
- if (mFacetPackageMap.containsKey(packageName)) {
- setCurrentFacet(mFacetPackageMap.get(packageName));
- }
-
- // Check if the package matches any of the categories for the facets
- String category = getPackageCategory(packageName);
- if (category != null) {
- setCurrentFacet(mFacetCategoryMap.get(category));
- }
-
- // Set up the persistent docked task if needed.
- boolean isHomeTask =
- taskInfo.configuration.windowConfiguration.getActivityType() == ACTIVITY_TYPE_HOME;
- if (mPersistentTaskIntent != null && !mStatusBar.hasDockedTask() && !isHomeTask) {
- mStatusBar.startActivityOnStack(mPersistentTaskIntent,
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
- }
- }
-
- public void onPackageChange(String packageName) {
- if (mFacetPackageMap.containsKey(packageName)) {
- int index = mFacetPackageMap.get(packageName);
- mFacetHasMultipleAppsCache.put(index, facetHasMultiplePackages(index));
- // No need to check categories because we've already refreshed the cache.
- return;
- }
-
- String category = getPackageCategory(packageName);
- if (mFacetCategoryMap.containsKey(category)) {
- int index = mFacetCategoryMap.get(category);
- mFacetHasMultipleAppsCache.put(index, facetHasMultiplePackages(index));
- }
- }
-
- /**
- * Iterates through the items in arrays_car.xml and sets up the facet bar buttons to
- * perform the task in that configuration file when clicked or long-pressed.
- */
- private void bind() {
- Resources res = mContext.getResources();
-
- TypedArray icons = res.obtainTypedArray(R.array.car_facet_icons);
- TypedArray intents = res.obtainTypedArray(R.array.car_facet_intent_uris);
- TypedArray longPressIntents = res.obtainTypedArray(R.array.car_facet_longpress_intent_uris);
- TypedArray facetPackageNames = res.obtainTypedArray(R.array.car_facet_package_filters);
- TypedArray facetCategories = res.obtainTypedArray(R.array.car_facet_category_filters);
-
- try {
- if (icons.length() != intents.length()
- || icons.length() != longPressIntents.length()
- || icons.length() != facetPackageNames.length()
- || icons.length() != facetCategories.length()) {
- throw new RuntimeException("car_facet array lengths do not match");
- }
-
- for (int i = 0, size = icons.length(); i < size; i++) {
- Drawable icon = icons.getDrawable(i);
- CarNavigationButton button = createNavButton(icon);
- initClickListeners(button, i, intents.getString(i), longPressIntents.getString(i));
-
- mNavButtons.add(button);
- mNavBar.addButton(button, createNavButton(icon) /* lightsOutButton */);
-
- initFacetFilterMaps(i, facetPackageNames.getString(i).split(FACET_FILTER_DELIMITER),
- facetCategories.getString(i).split(FACET_FILTER_DELIMITER));
- mFacetHasMultipleAppsCache.put(i, facetHasMultiplePackages(i));
- }
- } finally {
- // Clean up all the TypedArrays.
- icons.recycle();
- intents.recycle();
- longPressIntents.recycle();
- facetPackageNames.recycle();
- facetCategories.recycle();
- }
- }
-
- /**
- * Recreates each of the buttons on a density or font scale change. This manual process is
- * necessary since this class is not part of an activity that automatically gets recreated.
- */
- public void onDensityOrFontScaleChanged() {
- TypedArray icons = mContext.getResources().obtainTypedArray(R.array.car_facet_icons);
-
- try {
- int length = icons.length();
- if (length != mNavButtons.size()) {
- // This should not happen since the mNavButtons list is created from the length
- // of the icons array in bind().
- throw new RuntimeException("car_facet array lengths do not match number of "
- + "created buttons.");
- }
-
- for (int i = 0; i < length; i++) {
- Drawable icon = icons.getDrawable(i);
-
- // Setting a new icon will trigger a requestLayout() call if necessary.
- mNavButtons.get(i).setResources(icon);
- }
- } finally {
- icons.recycle();
- }
- }
-
- private void initFacetFilterMaps(int id, String[] packageNames, String[] categories) {
- mFacetCategories.add(categories);
- for (String category : categories) {
- mFacetCategoryMap.put(category, id);
- }
-
- mFacetPackages.add(packageNames);
- for (String packageName : packageNames) {
- mFacetPackageMap.put(packageName, id);
- }
- }
-
- private String getPackageCategory(String packageName) {
- PackageManager pm = mContext.getPackageManager();
- int size = mFacetCategories.size();
- // For each facet, check if the given package name matches one of its categories
- for (int i = 0; i < size; i++) {
- String[] categories = mFacetCategories.get(i);
- for (int j = 0; j < categories.length; j++) {
- String category = categories[j];
- Intent intent = new Intent();
- intent.setPackage(packageName);
- intent.setAction(Intent.ACTION_MAIN);
- intent.addCategory(category);
- List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
- if (list.size() > 0) {
- // Cache this package name into facetPackageMap, so we won't have to query
- // all categories next time this package name shows up.
- mFacetPackageMap.put(packageName, mFacetCategoryMap.get(category));
- return category;
- }
- }
- }
- return null;
- }
-
- /**
- * Helper method to check if a given facet has multiple packages associated with it. This can
- * be resource defined package names or package names filtered by facet category.
- *
- * @return {@code true} if the facet at the given index has more than one package.
- */
- private boolean facetHasMultiplePackages(int index) {
- PackageManager pm = mContext.getPackageManager();
-
- // Check if the packages defined for the filter actually exists on the device
- String[] packages = mFacetPackages.get(index);
- if (packages.length > 1) {
- int count = 0;
- for (int i = 0; i < packages.length; i++) {
- count += pm.getLaunchIntentForPackage(packages[i]) != null ? 1 : 0;
- if (count > 1) {
- return true;
- }
- }
- }
-
- // If there weren't multiple packages defined for the facet, check the categories
- // and see if they resolve to multiple package names
- String categories[] = mFacetCategories.get(index);
-
- int count = 0;
- for (int i = 0; i < categories.length; i++) {
- String category = categories[i];
- Intent intent = new Intent();
- intent.setAction(Intent.ACTION_MAIN);
- intent.addCategory(category);
- count += pm.queryIntentActivities(intent, 0).size();
- if (count > 1) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Sets the facet at the given index to be the facet that is currently active. The button will
- * be highlighted appropriately.
- */
- private void setCurrentFacet(int index) {
- if (index == mCurrentFacetIndex) {
- return;
- }
-
- if (mNavButtons.get(mCurrentFacetIndex) != null) {
- mNavButtons.get(mCurrentFacetIndex)
- .setSelected(false /* selected */, false /* showMoreIcon */);
- }
-
- if (mNavButtons.get(index) != null) {
- mNavButtons.get(index).setSelected(true /* selected */,
- mFacetHasMultipleAppsCache.get(index) /* showMoreIcon */);
- }
-
- mCurrentFacetIndex = index;
- }
-
- /**
- * Creates the View that is used for the buttons along the navigation bar.
- *
- * @param icon The icon to be used for the button.
- */
- private CarNavigationButton createNavButton(Drawable icon) {
- CarNavigationButton button = (CarNavigationButton) View.inflate(mContext,
- R.layout.car_navigation_button, null);
- button.setResources(icon);
- LinearLayout.LayoutParams lp =
- new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1);
- button.setLayoutParams(lp);
-
- return button;
- }
-
- /**
- * Initializes the click and long click listeners that correspond to the given command string.
- * The click listeners are attached to the given button.
- */
- private void initClickListeners(View button, int index, String clickString,
- String longPressString) {
- // Each button at least have an action when pressed.
- if (TextUtils.isEmpty(clickString)) {
- throw new RuntimeException("Facet at index " + index + " does not have click action.");
- }
-
- try {
- Intent intent = Intent.parseUri(clickString, Intent.URI_INTENT_SCHEME);
- button.setOnClickListener(v -> onFacetClicked(intent, index));
- } catch (URISyntaxException e) {
- throw new RuntimeException("Malformed intent uri", e);
- }
-
- if (TextUtils.isEmpty(longPressString)) {
- button.setLongClickable(false);
- return;
- }
-
- try {
- Intent intent = Intent.parseUri(longPressString, Intent.URI_INTENT_SCHEME);
- button.setOnLongClickListener(v -> {
- onFacetLongClicked(intent, index);
- return true;
- });
- } catch (URISyntaxException e) {
- throw new RuntimeException("Malformed long-press intent uri", e);
- }
- }
-
- /**
- * Handles a click on a facet. A click will trigger the given Intent.
- *
- * @param index The index of the facet that was clicked.
- */
- private void onFacetClicked(Intent intent, int index) {
- String packageName = intent.getPackage();
-
- if (packageName == null && !intent.getCategories().contains(Intent.CATEGORY_HOME)) {
- return;
- }
-
- intent.putExtra(EXTRA_FACET_CATEGORIES, mFacetCategories.get(index));
- intent.putExtra(EXTRA_FACET_PACKAGES, mFacetPackages.get(index));
- // The facet is identified by the index in which it was added to the nav bar.
- // This value can be used to determine which facet was selected
- intent.putExtra(EXTRA_FACET_ID, Integer.toString(index));
-
- // If the current facet is clicked, we want to launch the picker by default
- // rather than the "preferred/last run" app.
- intent.putExtra(EXTRA_FACET_LAUNCH_PICKER, index == mCurrentFacetIndex);
-
- int windowingMode = WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
- int activityType = ACTIVITY_TYPE_UNDEFINED;
- if (intent.getCategories().contains(Intent.CATEGORY_HOME)) {
- windowingMode = WINDOWING_MODE_UNDEFINED;
- activityType = ACTIVITY_TYPE_HOME;
- }
-
- setCurrentFacet(index);
- mStatusBar.startActivityOnStack(intent, windowingMode, activityType);
- }
-
- /**
- * Handles a long-press on a facet. The long-press will trigger the given Intent.
- *
- * @param index The index of the facet that was clicked.
- */
- private void onFacetLongClicked(Intent intent, int index) {
- setCurrentFacet(index);
- mStatusBar.startActivityOnStack(intent,
- WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_UNDEFINED);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
index e5a311d099d5..1d9ef616d98d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
@@ -16,17 +16,15 @@
package com.android.systemui.statusbar.car;
+import android.app.UiModeManager;
import android.content.Context;
-import android.graphics.Canvas;
import android.util.AttributeSet;
-import android.view.MotionEvent;
+import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
+import com.android.keyguard.AlphaOptimizedImageButton;
import com.android.systemui.R;
-import com.android.systemui.plugins.statusbar.phone.NavGesture;
-import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
-import com.android.systemui.statusbar.phone.NavigationBarView;
/**
* A custom navigation bar for the automotive use case.
@@ -34,9 +32,10 @@ import com.android.systemui.statusbar.phone.NavigationBarView;
* The navigation bar in the automotive use case is more like a list of shortcuts, rendered
* in a linear layout.
*/
-class CarNavigationBarView extends NavigationBarView {
+class CarNavigationBarView extends LinearLayout {
private LinearLayout mNavButtons;
- private LinearLayout mLightsOutButtons;
+ private AlphaOptimizedImageButton mNotificationsButton;
+ private CarStatusBar mCarStatusBar;
public CarNavigationBarView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -45,99 +44,16 @@ class CarNavigationBarView extends NavigationBarView {
@Override
public void onFinishInflate() {
mNavButtons = findViewById(R.id.nav_buttons);
- mLightsOutButtons = findViewById(R.id.lights_out);
- }
- public void addButton(CarNavigationButton button, CarNavigationButton lightsOutButton){
- mNavButtons.addView(button);
- mLightsOutButtons.addView(lightsOutButton);
+ mNotificationsButton = findViewById(R.id.notifications);
+ mNotificationsButton.setOnClickListener(this::onNotificationsClick);
}
- @Override
- public void setDisabledFlags(int disabledFlags, boolean force) {
- // TODO: Populate.
+ void setStatusBar(CarStatusBar carStatusBar) {
+ mCarStatusBar = carStatusBar;
}
- @Override
- public void reorient() {
- // We expect the car head unit to always have a fixed rotation so we ignore this. The super
- // class implentation expects mRotatedViews to be populated, so if you call into it, there
- // is a possibility of a NullPointerException.
- }
-
- @Override
- public View getCurrentView() {
- return this;
- }
-
- @Override
- public void setNavigationIconHints(int hints, boolean force) {
- // We do not need to set the navigation icon hints for a vehicle
- // Calling setNavigationIconHints in the base class will result in a NPE as the car
- // navigation bar does not have a back button.
- }
-
- @Override
- public void onPluginConnected(NavGesture plugin, Context context) {
- // set to null version of the plugin ignoring incoming arg.
- super.onPluginConnected(new NullNavGesture(), context);
- }
-
- @Override
- public void onPluginDisconnected(NavGesture plugin) {
- // reinstall the null nav gesture plugin
- super.onPluginConnected(new NullNavGesture(), getContext());
- }
-
- /**
- * Null object pattern to work around expectations of the base class.
- * This is a temporary solution to have the car system ui working.
- * Already underway is a refactor of they car sys ui as to not use this class
- * hierarchy.
- */
- private static class NullNavGesture implements NavGesture {
- @Override
- public GestureHelper getGestureHelper() {
- return new GestureHelper() {
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- return false;
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent event) {
- return false;
- }
-
- @Override
- public void setBarState(boolean vertical, boolean isRtl) {
- }
-
- @Override
- public void onDraw(Canvas canvas) {
- }
-
- @Override
- public void onDarkIntensityChange(float intensity) {
- }
-
- @Override
- public void onLayout(boolean changed, int left, int top, int right, int bottom) {
- }
- };
- }
-
- @Override
- public int getVersion() {
- return 0;
- }
-
- @Override
- public void onCreate(Context sysuiContext, Context pluginContext) {
- }
-
- @Override
- public void onDestroy() {
- }
+ protected void onNotificationsClick(View v) {
+ mCarStatusBar.togglePanel();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
index 2de358f1c292..0cdaec1432c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
@@ -1,72 +1,87 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
package com.android.systemui.statusbar.car;
import android.content.Context;
-import android.graphics.drawable.Drawable;
+import android.content.Intent;
+import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.ImageView;
-import android.widget.RelativeLayout;
-import com.android.keyguard.AlphaOptimizedImageButton;
import com.android.systemui.R;
+import java.net.URISyntaxException;
+
/**
- * A wrapper view for a car navigation facet, which includes a button icon and a drop down icon.
+ * CarNavigationButton is an image button that allows for a bit more configuration at the
+ * xml file level. This allows for more control via overlays instead of having to update
+ * code.
*/
-public class CarNavigationButton extends RelativeLayout {
+public class CarNavigationButton extends com.android.keyguard.AlphaOptimizedImageButton {
+
private static final float SELECTED_ALPHA = 1;
private static final float UNSELECTED_ALPHA = 0.7f;
- private AlphaOptimizedImageButton mIcon;
- private AlphaOptimizedImageButton mMoreIcon;
+ private Context mContext;
+ private String mIntent = null;
+ private String mLongIntent = null;
+ private boolean mBroadcastIntent = false;
+ private boolean mSelected = false;
+
public CarNavigationButton(Context context, AttributeSet attrs) {
super(context, attrs);
+ mContext = context;
+ TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CarNavigationButton);
+ mIntent = typedArray.getString(R.styleable.CarNavigationButton_intent);
+ mLongIntent = typedArray.getString(R.styleable.CarNavigationButton_longIntent);
+ mBroadcastIntent = typedArray.getBoolean(R.styleable.CarNavigationButton_broadcast, false);
}
+
+ /**
+ * After the standard inflate this then adds the xml defined intents to click and long click
+ * actions if defined.
+ */
@Override
public void onFinishInflate() {
super.onFinishInflate();
- mIcon = findViewById(R.id.car_nav_button_icon);
- mIcon.setScaleType(ImageView.ScaleType.CENTER);
- mIcon.setClickable(false);
- mIcon.setBackgroundColor(android.R.color.transparent);
- mIcon.setAlpha(UNSELECTED_ALPHA);
-
- mMoreIcon = findViewById(R.id.car_nav_button_more_icon);
- mMoreIcon.setClickable(false);
- mMoreIcon.setBackgroundColor(android.R.color.transparent);
- mMoreIcon.setVisibility(INVISIBLE);
- mMoreIcon.setImageDrawable(getContext().getDrawable(R.drawable.car_ic_arrow));
- mMoreIcon.setAlpha(UNSELECTED_ALPHA);
- }
+ setScaleType(ImageView.ScaleType.CENTER);
+ setAlpha(UNSELECTED_ALPHA);
+ try {
+ if (mIntent != null) {
+ final Intent intent = Intent.parseUri(mIntent, Intent.URI_INTENT_SCHEME);
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+ setOnClickListener(v -> {
+ if (mBroadcastIntent) {
+ mContext.sendBroadcast(intent);
+ return;
+ }
+ mContext.startActivity(intent);
+ });
+ }
+ } catch (URISyntaxException e) {
+ throw new RuntimeException("Failed to attach intent", e);
+ }
- public void setResources(Drawable icon) {
- mIcon.setImageDrawable(icon);
+ try {
+ if (mLongIntent != null) {
+ final Intent intent = Intent.parseUri(mLongIntent, Intent.URI_INTENT_SCHEME);
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+ setOnLongClickListener(v -> {
+ mContext.startActivity(intent);
+ return true;
+ });
+ }
+ } catch (URISyntaxException e) {
+ throw new RuntimeException("Failed to attach long press intent", e);
+ }
}
- public void setSelected(boolean selected, boolean showMoreIcon) {
- if (selected) {
- mMoreIcon.setVisibility(showMoreIcon ? VISIBLE : INVISIBLE);
- mMoreIcon.setAlpha(SELECTED_ALPHA);
- mIcon.setAlpha(SELECTED_ALPHA);
- } else {
- mMoreIcon.setVisibility(INVISIBLE);
- mIcon.setAlpha(UNSELECTED_ALPHA);
- }
+ /**
+ * @param selected true if should indicate if this is a selected state, false otherwise
+ */
+ public void setSelected(boolean selected) {
+ super.setSelected(selected);
+ mSelected = selected;
+ setAlpha(mSelected ? SELECTED_ALPHA : UNSELECTED_ALPHA);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 3dfb9130af2e..c15a01330534 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -18,17 +18,14 @@ package com.android.systemui.statusbar.car;
import android.app.ActivityManager;
import android.app.ActivityOptions;
-import android.content.BroadcastReceiver;
-import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.service.notification.StatusBarNotification;
import android.util.Log;
+import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
@@ -46,10 +43,7 @@ import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
-import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.statusbar.ExpandableNotificationRow;
-import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
import com.android.systemui.statusbar.phone.NavigationBarView;
@@ -69,7 +63,6 @@ public class CarStatusBar extends StatusBar implements
private TaskStackListenerImpl mTaskStackListener;
- private CarNavigationBarController mController;
private FullscreenUserSwitcher mFullscreenUserSwitcher;
private CarBatteryController mCarBatteryController;
@@ -78,15 +71,23 @@ public class CarStatusBar extends StatusBar implements
private ConnectedDeviceSignalController mConnectedDeviceSignalController;
private ViewGroup mNavigationBarWindow;
+ private ViewGroup mLeftNavigationBarWindow;
+ private ViewGroup mRightNavigationBarWindow;
private CarNavigationBarView mNavigationBarView;
+ private CarNavigationBarView mLeftNavigationBarView;
+ private CarNavigationBarView mRightNavigationBarView;
private final Object mQueueLock = new Object();
+ private boolean mShowLeft;
+ private boolean mShowRight;
+ private boolean mShowBottom;
+ private CarFacetButtonController mCarFacetButtonController;
+
@Override
public void start() {
super.start();
mTaskStackListener = new TaskStackListenerImpl();
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
- registerPackageChangeReceivers();
mStackScroller.setScrollingEnabled(true);
@@ -104,6 +105,16 @@ public class CarStatusBar extends StatusBar implements
mNavigationBarView = null;
}
+ if (mLeftNavigationBarWindow != null) {
+ mWindowManager.removeViewImmediate(mLeftNavigationBarWindow);
+ mLeftNavigationBarView = null;
+ }
+
+ if (mRightNavigationBarWindow != null) {
+ mWindowManager.removeViewImmediate(mRightNavigationBarWindow);
+ mRightNavigationBarView = null;
+ }
+
super.destroy();
}
@@ -153,10 +164,36 @@ public class CarStatusBar extends StatusBar implements
@Override
protected void createNavigationBar() {
+ mCarFacetButtonController = new CarFacetButtonController(mContext);
if (mNavigationBarView != null) {
return;
}
+ mShowBottom = mContext.getResources().getBoolean(R.bool.config_enableBottomNavigationBar);
+ if (mShowBottom) {
+ buildBottomBar();
+ }
+
+ int widthForSides = mContext.getResources().getDimensionPixelSize(
+ R.dimen.navigation_bar_height_car_mode);
+
+
+ mShowLeft = mContext.getResources().getBoolean(R.bool.config_enableLeftNavigationBar);
+
+ if (mShowLeft) {
+ buildLeft(widthForSides);
+ }
+
+ mShowRight = mContext.getResources().getBoolean(R.bool.config_enableRightNavigationBar);
+
+ if (mShowRight) {
+ buildRight(widthForSides);
+ }
+
+ }
+
+
+ private void buildBottomBar() {
// SystemUI requires that the navigation bar view have a parent. Since the regular
// StatusBar inflates navigation_bar_window as this parent view, use the same view for the
// CarNavigationBarView.
@@ -171,17 +208,15 @@ public class CarStatusBar extends StatusBar implements
mNavigationBarView = (CarNavigationBarView) mNavigationBarWindow.getChildAt(0);
if (mNavigationBarView == null) {
Log.e(TAG, "CarStatusBar failed inflate for R.layout.car_navigation_bar");
+ throw new RuntimeException("Unable to build botom nav bar due to missing layout");
}
+ mNavigationBarView.setStatusBar(this);
- mController = new CarNavigationBarController(mContext, mNavigationBarView,
- this /* ActivityStarter*/);
- mNavigationBarView.getBarTransitions().setAlwaysOpaque(true);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
- WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
@@ -189,9 +224,74 @@ public class CarStatusBar extends StatusBar implements
lp.setTitle("CarNavigationBar");
lp.windowAnimations = 0;
+
+ mCarFacetButtonController.addCarNavigationBar(mNavigationBarView);
mWindowManager.addView(mNavigationBarWindow, lp);
}
+ private void buildLeft(int widthForSides) {
+ mLeftNavigationBarWindow = (ViewGroup) View.inflate(mContext,
+ R.layout.navigation_bar_window, null);
+ if (mLeftNavigationBarWindow == null) {
+ Log.e(TAG, "CarStatusBar failed inflate for R.layout.navigation_bar_window");
+ }
+
+ View.inflate(mContext, R.layout.car_left_navigation_bar, mLeftNavigationBarWindow);
+ mLeftNavigationBarView = (CarNavigationBarView) mLeftNavigationBarWindow.getChildAt(0);
+ if (mLeftNavigationBarView == null) {
+ Log.e(TAG, "CarStatusBar failed inflate for R.layout.car_navigation_bar");
+ throw new RuntimeException("Unable to build left nav bar due to missing layout");
+ }
+ mLeftNavigationBarView.setStatusBar(this);
+ mCarFacetButtonController.addCarNavigationBar(mLeftNavigationBarView);
+
+ WindowManager.LayoutParams leftlp = new WindowManager.LayoutParams(
+ widthForSides, LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+ PixelFormat.TRANSLUCENT);
+ leftlp.setTitle("LeftCarNavigationBar");
+ leftlp.windowAnimations = 0;
+ leftlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
+ leftlp.gravity = Gravity.LEFT;
+ mWindowManager.addView(mLeftNavigationBarWindow, leftlp);
+ }
+
+
+ private void buildRight(int widthForSides) {
+ mRightNavigationBarWindow = (ViewGroup) View.inflate(mContext,
+ R.layout.navigation_bar_window, null);
+ if (mRightNavigationBarWindow == null) {
+ Log.e(TAG, "CarStatusBar failed inflate for R.layout.navigation_bar_window");
+ }
+
+ View.inflate(mContext, R.layout.car_right_navigation_bar, mRightNavigationBarWindow);
+ mRightNavigationBarView = (CarNavigationBarView) mRightNavigationBarWindow.getChildAt(0);
+ if (mRightNavigationBarView == null) {
+ Log.e(TAG, "CarStatusBar failed inflate for R.layout.car_navigation_bar");
+ throw new RuntimeException("Unable to build right nav bar due to missing layout");
+ }
+ mRightNavigationBarView.setStatusBar(this);
+ mCarFacetButtonController.addCarNavigationBar(mRightNavigationBarView);
+
+ WindowManager.LayoutParams rightlp = new WindowManager.LayoutParams(
+ widthForSides, LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+ PixelFormat.TRANSLUCENT);
+ rightlp.setTitle("RightCarNavigationBar");
+ rightlp.windowAnimations = 0;
+ rightlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
+ rightlp.gravity = Gravity.RIGHT;
+ mWindowManager.addView(mRightNavigationBarWindow, rightlp);
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
//When executing dump() funciton simultaneously, we need to serialize them
@@ -204,8 +304,8 @@ public class CarStatusBar extends StatusBar implements
}
pw.print(" mTaskStackListener="); pw.println(mTaskStackListener);
- pw.print(" mController=");
- pw.println(mController);
+ pw.print(" mCarFacetButtonController=");
+ pw.println(mCarFacetButtonController);
pw.print(" mFullscreenUserSwitcher="); pw.println(mFullscreenUserSwitcher);
pw.print(" mCarBatteryController=");
pw.println(mCarBatteryController);
@@ -229,10 +329,6 @@ public class CarStatusBar extends StatusBar implements
}
}
- @Override
- public NavigationBarView getNavigationBarView() {
- return mNavigationBarView;
- }
@Override
public View getNavigationBarWindow() {
@@ -269,24 +365,6 @@ public class CarStatusBar extends StatusBar implements
}
}
- private BroadcastReceiver mPackageChangeReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getData() == null || mController == null) {
- return;
- }
- String packageName = intent.getData().getSchemeSpecificPart();
- mController.onPackageChange(packageName);
- }
- };
-
- private void registerPackageChangeReceivers() {
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addDataScheme("package");
- mContext.registerReceiver(mPackageChangeReceiver, filter);
- }
public boolean hasDockedTask() {
return Recents.getSystemServices().hasDockedTask();
@@ -301,10 +379,7 @@ public class CarStatusBar extends StatusBar implements
public void onTaskStackChanged() {
ActivityManager.RunningTaskInfo runningTaskInfo =
ActivityManagerWrapper.getInstance().getRunningTask();
- if (runningTaskInfo != null && runningTaskInfo.baseActivity != null) {
- mController.taskChanged(runningTaskInfo.baseActivity.getPackageName(),
- runningTaskInfo);
- }
+ mCarFacetButtonController.taskChanged(runningTaskInfo);
}
}
@@ -346,33 +421,6 @@ public class CarStatusBar extends StatusBar implements
// Do nothing, we don't want to display media art in the lock screen for a car.
}
- private int startActivityWithOptions(Intent intent, Bundle options) {
- int result = ActivityManager.START_CANCELED;
- try {
- result = ActivityManager.getService().startActivityAsUser(null /* caller */,
- mContext.getBasePackageName(),
- intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- null /* resultTo*/,
- null /* resultWho*/,
- 0 /* requestCode*/,
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP,
- null /* profilerInfo*/,
- options,
- UserHandle.CURRENT.getIdentifier());
- } catch (RemoteException e) {
- Log.w(TAG, "Unable to start activity", e);
- }
-
- return result;
- }
-
- public int startActivityOnStack(Intent intent, int windowingMode, int activityType) {
- final ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchWindowingMode(windowingMode);
- options.setLaunchActivityType(activityType);
- return startActivityWithOptions(intent, options.toBundle());
- }
@Override
public void animateExpandNotificationsPanel() {
@@ -390,8 +438,6 @@ public class CarStatusBar extends StatusBar implements
@Override
public void onDensityOrFontScaleChanged() {
super.onDensityOrFontScaleChanged();
- mController.onDensityOrFontScaleChanged();
-
// Need to update the background on density changed in case the change was due to night
// mode.
mNotificationPanelBackground = getDefaultWallpaper();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 11d20b221051..ef44ad17e1c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -77,11 +77,11 @@ public class ActivityLaunchAnimator {
mStatusBar = statusBar;
}
- public ActivityOptions getLaunchAnimation(
- ExpandableNotificationRow sourceNofitication) {
- AnimationRunner animationRunner = new AnimationRunner(sourceNofitication);
- return ActivityOptions.makeRemoteAnimation(
- new RemoteAnimationAdapter(animationRunner, 1000 /* Duration */, 0 /* delay */));
+ public RemoteAnimationAdapter getLaunchAnimation(
+ ExpandableNotificationRow sourceNotification) {
+ AnimationRunner animationRunner = new AnimationRunner(sourceNotification);
+ return new RemoteAnimationAdapter(animationRunner, ANIMATION_DURATION,
+ 0 /* statusBarTransitionDelay */);
}
public boolean isAnimationPending() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 1239a9ea0240..79c605e4ed23 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -19,6 +19,7 @@ import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.windowStateToString;
+import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_WINDOW_STATE;
import static com.android.systemui.statusbar.phone.StatusBar.dumpBarTransitions;
@@ -71,7 +72,6 @@ import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
-import android.widget.Button;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -114,8 +114,6 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
/** Allow some time inbetween the long press for back and recents. */
private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
- private static final int BUTTON_FADE_IN_OUT_DURATION_MS = 100;
-
protected NavigationBarView mNavigationBarView = null;
protected AssistManager mAssistManager;
@@ -152,7 +150,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
private RotationLockController mRotationLockController;
private TaskStackListenerImpl mTaskStackListener;
- private final Runnable mRemoveRotationProposal = () -> setRotateSuggestionButtonState(false);
+ private final Runnable mRemoveRotationProposal = () -> safeSetRotationButtonState(false);
private Animator mRotateShowAnimator;
private Animator mRotateHideAnimator;
@@ -167,6 +165,11 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
public void onRecentsAnimationStarted() {
mNavigationBarView.setRecentsAnimationStarted(true);
}
+
+ @Override
+ public void onInteractionFlagsChanged(@InteractionType int flags) {
+ mNavigationBarView.updateStates();
+ }
};
// ----- Fragment Lifecycle Callbacks -----
@@ -361,22 +364,32 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
// rotate button if shown.
if (!isValid) {
- setRotateSuggestionButtonState(false);
+ safeSetRotationButtonState(false);
return;
}
if (rotation == mWindowManager.getDefaultDisplay().getRotation()) {
// Use this as a signal to remove any current suggestions
getView().getHandler().removeCallbacks(mRemoveRotationProposal);
- setRotateSuggestionButtonState(false);
+ safeSetRotationButtonState(false);
} else {
mLastRotationSuggestion = rotation; // Remember rotation for click
- setRotateSuggestionButtonState(true);
+ safeSetRotationButtonState(true);
rescheduleRotationTimeout(false);
mMetricsLogger.visible(MetricsEvent.ROTATION_SUGGESTION_SHOWN);
}
}
+ private void safeSetRotationButtonState(boolean vis) {
+ if (mNavigationBarView != null) mNavigationBarView.setRotateSuggestionButtonState(vis);
+ }
+
+ private void safeSetRotationButtonState(boolean vis, boolean force) {
+ if (mNavigationBarView != null) {
+ mNavigationBarView.setRotateSuggestionButtonState(vis, force);
+ }
+ }
+
private void rescheduleRotationTimeout(final boolean reasonHover) {
// May be called due to a new rotation proposal or a change in hover state
if (reasonHover) {
@@ -402,84 +415,6 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
return 6000;
}
- public void setRotateSuggestionButtonState(final boolean visible) {
- setRotateSuggestionButtonState(visible, false);
- }
-
- public void setRotateSuggestionButtonState(final boolean visible, final boolean skipAnim) {
- ButtonDispatcher rotBtn = mNavigationBarView.getRotateSuggestionButton();
- final boolean currentlyVisible = rotBtn.getVisibility() == View.VISIBLE;
-
- // Rerun a show animation to indicate change but don't rerun a hide animation
- if (!visible && !currentlyVisible) return;
-
- View currentView = rotBtn.getCurrentView();
- if (currentView == null) return;
-
- KeyButtonDrawable kbd = rotBtn.getImageDrawable();
- if (kbd == null) return;
-
- AnimatedVectorDrawable animIcon = null;
- if (kbd.getDrawable(0) instanceof AnimatedVectorDrawable) {
- animIcon = (AnimatedVectorDrawable) kbd.getDrawable(0);
- }
-
- if (visible) { // Appear and change
- rotBtn.setVisibility(View.VISIBLE);
- mNavigationBarView.notifySubtreeAccessibilityStateChangedIfNeeded();
-
- if (skipAnim) {
- currentView.setAlpha(1f);
- return;
- }
-
- // Start a new animation if running
- if (mRotateShowAnimator != null) mRotateShowAnimator.pause();
- if (mRotateHideAnimator != null) mRotateHideAnimator.pause();
-
- ObjectAnimator appearFade = ObjectAnimator.ofFloat(currentView, "alpha",
- 0f, 1f);
- appearFade.setDuration(BUTTON_FADE_IN_OUT_DURATION_MS);
- appearFade.setInterpolator(Interpolators.LINEAR);
- mRotateShowAnimator = appearFade;
- appearFade.start();
-
- // Run the rotate icon's animation if it has one
- if (animIcon != null) {
- animIcon.reset();
- animIcon.start();
- }
-
- } else { // Hide
-
- if (skipAnim) {
- rotBtn.setVisibility(View.INVISIBLE);
- mNavigationBarView.notifySubtreeAccessibilityStateChangedIfNeeded();
- return;
- }
-
- // Don't start any new hide animations if one is running
- if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) return;
- // Pause any active show animations but don't reset the AVD to avoid jumps
- if (mRotateShowAnimator != null) mRotateShowAnimator.pause();
-
- ObjectAnimator fadeOut = ObjectAnimator.ofFloat(currentView, "alpha",
- 0f);
- fadeOut.setDuration(BUTTON_FADE_IN_OUT_DURATION_MS);
- fadeOut.setInterpolator(Interpolators.LINEAR);
- fadeOut.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- rotBtn.setVisibility(View.INVISIBLE);
- mNavigationBarView.notifySubtreeAccessibilityStateChangedIfNeeded();
- }
- });
-
- mRotateHideAnimator = fadeOut;
- fadeOut.start();
- }
- }
-
// Injected from StatusBar at creation.
public void setCurrentSysuiVisibility(int systemUiVisibility) {
mSystemUiVisibility = systemUiVisibility;
@@ -892,7 +827,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
if (shouldOverrideUserLockPrefs(rotation)) {
mRotationLockController.setRotationLockedAtAngle(true, rotation);
}
- setRotateSuggestionButtonState(false, true);
+ safeSetRotationButtonState(false, true);
}
if (mNavigationBarView != null
@@ -928,22 +863,22 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
@Override
public void onTaskStackChanged() {
- setRotateSuggestionButtonState(false);
+ safeSetRotationButtonState(false);
}
@Override
public void onTaskRemoved(int taskId) {
- setRotateSuggestionButtonState(false);
+ safeSetRotationButtonState(false);
}
@Override
public void onTaskMovedToFront(int taskId) {
- setRotateSuggestionButtonState(false);
+ safeSetRotationButtonState(false);
}
@Override
public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) {
- setRotateSuggestionButtonState(false);
+ safeSetRotationButtonState(false);
}
}
@@ -960,6 +895,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
PixelFormat.TRANSLUCENT);
lp.token = new Binder();
lp.setTitle("NavigationBar");
+ lp.accessibilityTitle = context.getString(R.string.nav_bar);
lp.windowAnimations = 0;
View navigationBarView = LayoutInflater.from(context).inflate(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index d15c771ec098..4454ef9f411c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -127,10 +127,13 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture
private boolean proxyMotionEvents(MotionEvent event) {
final IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
- if (overviewProxy != null) {
+ if (overviewProxy != null && mNavigationBarView.isQuickStepSwipeUpEnabled()) {
mNavigationBarView.requestUnbufferedDispatch(event);
event.transform(mTransformGlobalMatrix);
try {
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ overviewProxy.onPreMotionEvent(mNavigationBarView.getDownHitTarget());
+ }
overviewProxy.onMotionEvent(event);
if (DEBUG_OVERVIEW_PROXY) {
Log.d(TAG_OPS, "Send MotionEvent: " + event.toString());
@@ -146,8 +149,12 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture
}
public boolean onInterceptTouchEvent(MotionEvent event) {
- int action = event.getAction();
- switch (action & MotionEvent.ACTION_MASK) {
+ if (mNavigationBarView.inScreenPinning()) {
+ return false;
+ }
+
+ int action = event.getActionMasked();
+ switch (action) {
case MotionEvent.ACTION_DOWN: {
mTouchDownX = (int) event.getX();
mTouchDownY = (int) event.getY();
@@ -174,6 +181,10 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture
}
public boolean onTouchEvent(MotionEvent event) {
+ if (mNavigationBarView.inScreenPinning()) {
+ return false;
+ }
+
// The same down event was just sent on intercept and therefore can be ignored here
boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN
&& mOverviewProxyService.getProxy() != null;
@@ -189,7 +200,7 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture
}
public void onDraw(Canvas canvas) {
- if (mOverviewProxyService.getProxy() != null) {
+ if (mNavigationBarView.isQuickScrubEnabled()) {
mQuickScrubController.onDraw(canvas);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index 9d20e4e1bb87..989423530599 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -57,13 +57,12 @@ public class NavigationBarInflaterView extends FrameLayout
public static final String NAV_BAR_LEFT = "sysui_nav_bar_left";
public static final String NAV_BAR_RIGHT = "sysui_nav_bar_right";
- public static final String MENU_IME = "menu_ime";
+ public static final String MENU_IME_ROTATE = "menu_ime";
public static final String BACK = "back";
public static final String HOME = "home";
public static final String RECENT = "recent";
public static final String NAVSPACE = "space";
public static final String CLIPBOARD = "clipboard";
- public static final String ROTATE = "rotate";
public static final String KEY = "key";
public static final String LEFT = "left";
public static final String RIGHT = "right";
@@ -317,10 +316,10 @@ public class NavigationBarInflaterView extends FrameLayout
View v = null;
String button = extractButton(buttonSpec);
if (LEFT.equals(button)) {
- String s = Dependency.get(TunerService.class).getValue(NAV_BAR_LEFT, ROTATE);
+ String s = Dependency.get(TunerService.class).getValue(NAV_BAR_LEFT, NAVSPACE);
button = extractButton(s);
} else if (RIGHT.equals(button)) {
- String s = Dependency.get(TunerService.class).getValue(NAV_BAR_RIGHT, MENU_IME);
+ String s = Dependency.get(TunerService.class).getValue(NAV_BAR_RIGHT, MENU_IME_ROTATE);
button = extractButton(s);
}
// Let plugins go first so they can override a standard view if they want.
@@ -334,14 +333,12 @@ public class NavigationBarInflaterView extends FrameLayout
v = inflater.inflate(R.layout.back, parent, false);
} else if (RECENT.equals(button)) {
v = inflater.inflate(R.layout.recent_apps, parent, false);
- } else if (MENU_IME.equals(button)) {
+ } else if (MENU_IME_ROTATE.equals(button)) {
v = inflater.inflate(R.layout.menu_ime, parent, false);
} else if (NAVSPACE.equals(button)) {
v = inflater.inflate(R.layout.nav_key_space, parent, false);
} else if (CLIPBOARD.equals(button)) {
v = inflater.inflate(R.layout.clipboard, parent, false);
- } else if (ROTATE.equals(button)) {
- v = inflater.inflate(R.layout.rotate_suggestion, parent, false);
} else if (button.startsWith(KEY)) {
String uri = extractImage(button);
int code = extractKeycode(button);
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 af0afbdd6782..285980b39020 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -16,6 +16,13 @@
package com.android.systemui.statusbar.phone;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_BACK;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.LayoutTransition;
import android.animation.LayoutTransition.TransitionListener;
import android.animation.ObjectAnimator;
@@ -29,9 +36,11 @@ import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.drawable.AnimatedVectorDrawable;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.support.annotation.ColorInt;
import android.util.AttributeSet;
import android.util.Log;
@@ -49,6 +58,7 @@ import android.widget.FrameLayout;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.DockedStackExistsListener;
+import com.android.systemui.Interpolators;
import com.android.systemui.OverviewProxyService;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
@@ -57,6 +67,8 @@ import com.android.systemui.plugins.PluginManager;
import com.android.systemui.plugins.statusbar.phone.NavGesture;
import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
import com.android.systemui.recents.RecentsOnboarding;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.NavigationBarCompat;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.policy.DeadZone;
import com.android.systemui.statusbar.policy.KeyButtonDrawable;
@@ -66,10 +78,17 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.function.Consumer;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_QUICK_SCRUB;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_HIDE_BACK_BUTTON;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
+
public class NavigationBarView extends FrameLayout implements PluginListener<NavGesture> {
final static boolean DEBUG = false;
final static String TAG = "StatusBar/NavBarView";
+ final static int BUTTON_FADE_IN_OUT_DURATION_MS = 100;
+
// slippery nav bar when everything is disabled, e.g. during setup
final static boolean SLIPPERY_WHEN_DISABLED = true;
@@ -85,9 +104,15 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
boolean mShowMenu;
boolean mShowAccessibilityButton;
boolean mLongClickableAccessibilityButton;
+ boolean mShowRotateButton;
int mDisabledFlags = 0;
int mNavigationIconHints = 0;
+ private @NavigationBarCompat.HitTarget int mDownHitTarget = HIT_TARGET_NONE;
+ private Rect mHomeButtonBounds = new Rect();
+ private Rect mBackButtonBounds = new Rect();
+ private int[] mTmpPosition = new int[2];
+
private KeyButtonDrawable mBackIcon, mBackLandIcon, mBackAltIcon, mBackAltLandIcon;
private KeyButtonDrawable mBackCarModeIcon, mBackLandCarModeIcon;
private KeyButtonDrawable mBackAltCarModeIcon, mBackAltLandCarModeIcon;
@@ -127,6 +152,8 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
private RecentsOnboarding mRecentsOnboarding;
private NotificationPanelView mPanelView;
+ private Animator mRotateHideAnimator;
+
private class NavTransitionListener implements TransitionListener {
private boolean mBackTransitioning;
private boolean mHomeAppearing;
@@ -217,6 +244,9 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
mShowAccessibilityButton = false;
mLongClickableAccessibilityButton = false;
+ mOverviewProxyService = Dependency.get(OverviewProxyService.class);
+ mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
+
mConfiguration = new Configuration();
mConfiguration.updateFrom(context.getResources().getConfiguration());
updateIcons(context, Configuration.EMPTY, mConfiguration);
@@ -232,9 +262,6 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
new ButtonDispatcher(R.id.accessibility_button));
mButtonDispatchers.put(R.id.rotate_suggestion,
new ButtonDispatcher(R.id.rotate_suggestion));
-
- mOverviewProxyService = Dependency.get(OverviewProxyService.class);
- mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
}
public BarTransitions getBarTransitions() {
@@ -275,6 +302,18 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
+ switch (event.getActionMasked()) {
+ case ACTION_DOWN:
+ int x = (int) event.getX();
+ int y = (int) event.getY();
+ mDownHitTarget = HIT_TARGET_NONE;
+ if (mBackButtonBounds.contains(x, y)) {
+ mDownHitTarget = HIT_TARGET_BACK;
+ } else if (mHomeButtonBounds.contains(x, y)) {
+ mDownHitTarget = HIT_TARGET_HOME;
+ }
+ break;
+ }
return mGestureHelper.onInterceptTouchEvent(event);
}
@@ -286,6 +325,10 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
return super.onTouchEvent(event);
}
+ public @NavigationBarCompat.HitTarget int getDownHitTarget() {
+ return mDownHitTarget;
+ }
+
public void abortCurrentGesture() {
getHomeButton().abortCurrentGesture();
}
@@ -336,6 +379,19 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
return getRecentsButton().getVisibility() == View.VISIBLE;
}
+ public boolean isQuickStepSwipeUpEnabled() {
+ return mOverviewProxyService.getProxy() != null
+ && ((mOverviewProxyService.getInteractionFlags()
+ & FLAG_DISABLE_SWIPE_UP) == 0);
+ }
+
+ public boolean isQuickScrubEnabled() {
+ return SystemProperties.getBoolean("persist.quickstep.scrub.enabled", true)
+ && mOverviewProxyService.getProxy() != null && !isRecentsButtonVisible()
+ && ((mOverviewProxyService.getInteractionFlags()
+ & FLAG_DISABLE_QUICK_SCRUB) == 0);
+ }
+
private void updateCarModeIcons(Context ctx) {
mBackCarModeIcon = getDrawable(ctx,
R.drawable.ic_sysbar_back_carmode, R.drawable.ic_sysbar_back_carmode);
@@ -352,17 +408,14 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
|| oldConfig.densityDpi != newConfig.densityDpi) {
mDockedIcon = getDrawable(ctx,
R.drawable.ic_sysbar_docked, R.drawable.ic_sysbar_docked_dark);
+ mHomeDefaultIcon = getHomeDrawable(ctx);
}
if (oldConfig.densityDpi != newConfig.densityDpi
|| oldConfig.getLayoutDirection() != newConfig.getLayoutDirection()) {
- mBackIcon = getDrawable(ctx, R.drawable.ic_sysbar_back, R.drawable.ic_sysbar_back_dark);
+ mBackIcon = getBackDrawable(ctx);
mBackLandIcon = mBackIcon;
- mBackAltIcon = getDrawable(ctx,
- R.drawable.ic_sysbar_back_ime, R.drawable.ic_sysbar_back_ime_dark);
+ mBackAltIcon = getBackImeDrawable(ctx);
mBackAltLandIcon = mBackAltIcon;
-
- mHomeDefaultIcon = getDrawable(ctx,
- R.drawable.ic_sysbar_home, R.drawable.ic_sysbar_home_dark);
mRecentIcon = getDrawable(ctx,
R.drawable.ic_sysbar_recent, R.drawable.ic_sysbar_recent_dark);
mMenuIcon = getDrawable(ctx, R.drawable.ic_sysbar_menu, R.drawable.ic_sysbar_menu_dark);
@@ -387,6 +440,33 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
}
}
+ public KeyButtonDrawable getBackDrawable(Context ctx) {
+ return chooseNavigationIconDrawable(ctx, R.drawable.ic_sysbar_back,
+ R.drawable.ic_sysbar_back_dark, R.drawable.ic_sysbar_back_quick_step,
+ R.drawable.ic_sysbar_back_quick_step_dark);
+ }
+
+ public KeyButtonDrawable getBackImeDrawable(Context ctx) {
+ return chooseNavigationIconDrawable(ctx, R.drawable.ic_sysbar_back_ime,
+ R.drawable.ic_sysbar_back_ime_dark, R.drawable.ic_sysbar_back_ime_quick_step,
+ R.drawable.ic_sysbar_back_ime_quick_step_dark);
+ }
+
+ public KeyButtonDrawable getHomeDrawable(Context ctx) {
+ return chooseNavigationIconDrawable(ctx, R.drawable.ic_sysbar_home,
+ R.drawable.ic_sysbar_home_dark, R.drawable.ic_sysbar_home_quick_step,
+ R.drawable.ic_sysbar_home_quick_step_dark);
+ }
+
+ private KeyButtonDrawable chooseNavigationIconDrawable(Context ctx, @DrawableRes int iconLight,
+ @DrawableRes int iconDark, @DrawableRes int quickStepIconLight,
+ @DrawableRes int quickStepIconDark) {
+ final boolean quickStepEnabled = isQuickStepSwipeUpEnabled() || isQuickScrubEnabled();
+ return quickStepEnabled
+ ? getDrawable(ctx, quickStepIconLight, quickStepIconDark)
+ : getDrawable(ctx, iconLight, iconDark);
+ }
+
private KeyButtonDrawable getDrawable(Context ctx, @DrawableRes int lightIcon,
@DrawableRes int darkIcon) {
return getDrawable(ctx, ctx, lightIcon, darkIcon);
@@ -462,22 +542,25 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
getHomeButton().setImageDrawable(mHomeDefaultIcon);
}
- // The Accessibility button always overrides the appearance of the IME switcher
+ // Update IME button visibility, a11y and rotate button always overrides the appearance
final boolean showImeButton =
- !mShowAccessibilityButton && ((hints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN)
- != 0);
+ !mShowAccessibilityButton &&
+ !mShowRotateButton &&
+ ((hints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
getImeSwitchButton().setVisibility(showImeButton ? View.VISIBLE : View.INVISIBLE);
getImeSwitchButton().setImageDrawable(mImeIcon);
- // Update menu button in case the IME state has changed.
+ // Update menu button, visibility logic in method
setMenuVisibility(mShowMenu, true);
getMenuButton().setImageDrawable(mMenuIcon);
+ // Update rotate button, visibility altered by a11y button logic
+ getRotateSuggestionButton().setImageDrawable(mRotateSuggestionIcon);
+
+ // Update a11y button, visibility logic in state method
setAccessibilityButtonState(mShowAccessibilityButton, mLongClickableAccessibilityButton);
getAccessibilityButton().setImageDrawable(mAccessibilityIcon);
- getRotateSuggestionButton().setImageDrawable(mRotateSuggestionIcon);
-
setDisabledFlags(mDisabledFlags, true);
mBarTransitions.reapplyDarkIntensity();
@@ -492,7 +575,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
mDisabledFlags = disabledFlags;
- final boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
+ boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
// Always disable recents when alternate car mode UI is active.
boolean disableRecent = mUseCarModeUi
@@ -501,15 +584,21 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
&& ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) == 0);
- if ((disableRecent || disableBack) && inScreenPinning()) {
- // Don't hide back and recents buttons when in screen pinning mode, as they are used for
- // exiting.
- disableBack = false;
- disableRecent = false;
- }
+ // When screen pinning, don't hide back and home when connected service or back and
+ // recents buttons when disconnected from launcher service in screen pinning mode,
+ // as they are used for exiting.
if (mOverviewProxyService.getProxy() != null) {
- // When overview is connected to the launcher service, disable the recents button
- disableRecent = true;
+ // Use interaction flags to show/hide navigation buttons but will be shown if required
+ // to exit screen pinning.
+ final int flags = mOverviewProxyService.getInteractionFlags();
+ disableRecent |= (flags & FLAG_SHOW_OVERVIEW_BUTTON) == 0;
+ if (inScreenPinning()) {
+ disableBack = disableHome = false;
+ } else {
+ disableBack |= (flags & FLAG_HIDE_BACK_BUTTON) != 0;
+ }
+ } else if (inScreenPinning()) {
+ disableBack = disableRecent = false;
}
ViewGroup navButtons = (ViewGroup) getCurrentView().findViewById(R.id.nav_buttons);
@@ -527,13 +616,8 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
}
- private boolean inScreenPinning() {
- try {
- return ActivityManager.getService().getLockTaskModeState()
- == ActivityManager.LOCK_TASK_MODE_PINNED;
- } catch (RemoteException e) {
- return false;
- }
+ public boolean inScreenPinning() {
+ return ActivityManagerWrapper.getInstance().isLockToAppActive();
}
public void setLayoutTransitionsEnabled(boolean enabled) {
@@ -587,6 +671,11 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
updateSlippery();
}
+ public void updateStates() {
+ updateSlippery();
+ setDisabledFlags(mDisabledFlags, true);
+ }
+
private void updateSlippery() {
setSlippery(mOverviewProxyService.getProxy() != null && mPanelView.isFullyExpanded());
}
@@ -621,8 +710,10 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
mShowMenu = show;
- // Only show Menu if IME switcher and Accessibility button not shown.
- final boolean shouldShow = mShowMenu && !mShowAccessibilityButton &&
+ // Only show Menu if IME switcher, rotate and Accessibility buttons are not shown.
+ final boolean shouldShow = mShowMenu &&
+ !mShowAccessibilityButton &&
+ !mShowRotateButton &&
((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) == 0);
getMenuButton().setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE);
@@ -632,15 +723,96 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
mShowAccessibilityButton = visible;
mLongClickableAccessibilityButton = longClickable;
if (visible) {
- // Accessibility button overrides Menu and IME switcher buttons.
+ // Accessibility button overrides Menu, IME switcher and rotate buttons.
setMenuVisibility(false, true);
getImeSwitchButton().setVisibility(View.INVISIBLE);
+ setRotateSuggestionButtonState(false, true);
}
getAccessibilityButton().setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
getAccessibilityButton().setLongClickable(longClickable);
}
+ public void setRotateSuggestionButtonState(final boolean visible) {
+ setRotateSuggestionButtonState(visible, false);
+ }
+
+ public void setRotateSuggestionButtonState(final boolean visible, final boolean force) {
+ ButtonDispatcher rotBtn = getRotateSuggestionButton();
+ final boolean currentlyVisible = mShowRotateButton;
+
+ // Rerun a show animation to indicate change but don't rerun a hide animation
+ if (!visible && !currentlyVisible) return;
+
+ View currentView = rotBtn.getCurrentView();
+ if (currentView == null) return;
+
+ KeyButtonDrawable kbd = rotBtn.getImageDrawable();
+ if (kbd == null) return;
+
+ AnimatedVectorDrawable animIcon = null;
+ if (kbd.getDrawable(0) instanceof AnimatedVectorDrawable) {
+ animIcon = (AnimatedVectorDrawable) kbd.getDrawable(0);
+ }
+
+ if (visible) { // Appear and change, cannot force
+ setRotateButtonVisibility(true);
+
+ // Stop any currently running hide animations
+ if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) {
+ mRotateHideAnimator.pause();
+ }
+
+ // Reset the alpha if any has changed due to hide animation
+ currentView.setAlpha(1f);
+
+ // Run the rotate icon's animation if it has one
+ if (animIcon != null) {
+ animIcon.reset();
+ animIcon.start();
+ }
+
+ } else { // Hide
+ if (force) {
+ // If a hide animator is running stop it and instantly make invisible
+ if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) {
+ mRotateHideAnimator.pause();
+ }
+ setRotateButtonVisibility(false);
+ return;
+ }
+
+ // Don't start any new hide animations if one is running
+ if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) return;
+
+ ObjectAnimator fadeOut = ObjectAnimator.ofFloat(currentView, "alpha",
+ 0f);
+ fadeOut.setDuration(BUTTON_FADE_IN_OUT_DURATION_MS);
+ fadeOut.setInterpolator(Interpolators.LINEAR);
+ fadeOut.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ setRotateButtonVisibility(false);
+ }
+ });
+
+ mRotateHideAnimator = fadeOut;
+ fadeOut.start();
+ }
+ }
+
+ private void setRotateButtonVisibility(final boolean visible) {
+ // Never show if a11y is visible
+ final boolean adjVisible = visible && !mShowAccessibilityButton;
+ final int vis = adjVisible ? View.VISIBLE : View.INVISIBLE;
+
+ getRotateSuggestionButton().setVisibility(vis);
+ mShowRotateButton = visible;
+
+ // Hide/restore other button visibility, if necessary
+ setNavigationIconHints(mNavigationIconHints, true);
+ }
+
@Override
public void onFinishInflate() {
mNavigationInflaterView = (NavigationBarInflaterView) findViewById(
@@ -663,9 +835,10 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
}
public void onOverviewProxyConnectionChanged(boolean isConnected) {
- setSlippery(!isConnected);
- setDisabledFlags(mDisabledFlags, true);
- setUpSwipeUpOnboarding(isConnected);
+ updateStates();
+ setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
+ updateIcons(getContext(), Configuration.EMPTY, mConfiguration);
+ setNavigationIconHints(mNavigationIconHints, true);
}
@Override
@@ -677,9 +850,23 @@ 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);
mGestureHelper.onLayout(changed, left, top, right, bottom);
}
+ private void updateButtonLocationOnScreen(ButtonDispatcher button, Rect buttonBounds) {
+ View view = button.getCurrentView();
+ if (view == null) {
+ buttonBounds.setEmpty();
+ return;
+ }
+ view.getLocationInWindow(mTmpPosition);
+ buttonBounds.set(mTmpPosition[0], mTmpPosition[1],
+ mTmpPosition[0] + view.getMeasuredWidth(),
+ mTmpPosition[1] + view.getMeasuredHeight());
+ }
+
private void updateRotatedViews() {
mRotatedViews[Surface.ROTATION_0] =
mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
@@ -734,6 +921,11 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
Log.d(TAG, "reorient(): rot=" + mCurrentRotation);
}
+ // Resolve layout direction if not resolved since components changing layout direction such
+ // as changing languages will recreate this view and the direction will be resolved later
+ if (!isLayoutDirectionResolved()) {
+ resolveLayoutDirection();
+ }
updateTaskSwitchHelper();
setNavigationIconHints(mNavigationIconHints, true);
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 0e8fcbabf2ae..3b129fc5e08d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -501,7 +501,8 @@ public class NotificationPanelView extends PanelView implements
float shelfSize = shelf.getVisibility() == GONE ? 0
: shelf.getIntrinsicHeight() + notificationPadding;
float availableSpace = mNotificationStackScroller.getHeight() - minPadding - shelfSize
- - Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);
+ - Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding)
+ - mKeyguardStatusView.getLogoutButtonHeight();
int count = 0;
for (int i = 0; i < mNotificationStackScroller.getChildCount(); i++) {
ExpandableView child = (ExpandableView) mNotificationStackScroller.getChildAt(i);
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 6444cc816663..747a551defe6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -575,7 +575,7 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks,
Intent browserIntent = getTaskIntent(taskId, userId);
Notification.Builder builder = new Notification.Builder(mContext, NotificationChannels.GENERAL);
- if (browserIntent != null) {
+ if (browserIntent != null && browserIntent.isWebIntent()) {
// Make sure that this doesn't resolve back to an instant app
browserIntent.setComponent(null)
.setPackage(null)
@@ -597,8 +597,9 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks,
.addCategory("unique:" + System.currentTimeMillis())
.putExtra(Intent.EXTRA_PACKAGE_NAME, appInfo.packageName)
.putExtra(Intent.EXTRA_VERSION_CODE, (int) (appInfo.versionCode & 0x7fffffff))
- .putExtra(Intent.EXTRA_VERSION_CODE, appInfo.versionCode)
- .putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, pendingIntent);
+ .putExtra(Intent.EXTRA_LONG_VERSION_CODE, appInfo.versionCode)
+ .putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, pendingIntent)
+ .putExtra(Intent.EXTRA_INSTANT_APP_FAILURE, pendingIntent);
PendingIntent webPendingIntent = PendingIntent.getActivity(mContext, 0, goToWebIntent, 0);
Action webAction = new Notification.Action.Builder(null, mContext.getString(R.string.go_to_web),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
index dc0835e4371a..378858a9b816 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
@@ -29,15 +29,12 @@ import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
-import android.os.SystemProperties;
import android.util.Log;
import android.util.Slog;
-import android.view.Display;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
-import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
@@ -53,6 +50,7 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
import static com.android.systemui.OverviewProxyService.TAG_OPS;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME;
/**
* Class to detect gestures on the navigation bar and implement quick scrub and switch.
@@ -88,11 +86,11 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
private int mLightTrackColor;
private int mDarkTrackColor;
private float mDarkIntensity;
+ private View mHomeButtonView;
private final Handler mHandler = new Handler();
private final Interpolator mQuickScrubEndInterpolator = new DecelerateInterpolator();
private final Rect mTrackRect = new Rect();
- private final Rect mHomeButtonRect = new Rect();
private final Paint mTrackPaint = new Paint();
private final int mScrollTouchSlop;
private final OverviewProxyService mOverviewEventSender;
@@ -114,11 +112,10 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
if (!mQuickScrubActive) {
pos = mDragPositive ? Math.min((int) mTranslation, pos) : Math.max((int) mTranslation, pos);
}
- final View homeView = mNavigationBarView.getHomeButton().getCurrentView();
if (mIsVertical) {
- homeView.setTranslationY(pos);
+ mHomeButtonView.setTranslationY(pos);
} else {
- homeView.setTranslationX(pos);
+ mHomeButtonView.setTranslationX(pos);
}
};
@@ -126,6 +123,7 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
@Override
public void onAnimationEnd(Animator animation) {
mNavigationBarView.getHomeButton().setClickable(true);
+ mHomeButtonView = null;
mQuickScrubActive = false;
mTranslation = 0;
}
@@ -137,8 +135,9 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velX, float velY) {
- if (!isQuickScrubEnabled() || mQuickScrubActive || !mAllowQuickSwitch ||
- !mHomeButtonRect.contains(mTouchDownX, mTouchDownY)) {
+ if (!mNavigationBarView.isQuickScrubEnabled() || mQuickScrubActive
+ || !mAllowQuickSwitch
+ || mNavigationBarView.getDownHitTarget() != HIT_TARGET_HOME) {
return false;
}
float velocityX = mIsRTL ? -velX : velX;
@@ -195,9 +194,8 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
final ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
- if (overviewProxy == null) {
+ if (!mNavigationBarView.isQuickScrubEnabled()) {
homeButton.setDelayTouchFeedback(false);
return false;
}
@@ -226,7 +224,13 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
case MotionEvent.ACTION_DOWN: {
int x = (int) event.getX();
int y = (int) event.getY();
- if (isQuickScrubEnabled() && mHomeButtonRect.contains(x, y)) {
+ // End any existing quickscrub animations before starting the new transition
+ if (mQuickScrubEndAnimator != null) {
+ mQuickScrubEndAnimator.end();
+ }
+ mHomeButtonView = homeButton.getCurrentView();
+ if (mNavigationBarView.isQuickScrubEnabled()
+ && mNavigationBarView.getDownHitTarget() == HIT_TARGET_HOME) {
mTouchDownX = x;
mTouchDownY = y;
homeButton.setDelayTouchFeedback(true);
@@ -293,7 +297,7 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
: Utilities.clamp(offset - mDownOffset, 0, trackSize);
if (mQuickScrubActive) {
try {
- overviewProxy.onQuickScrubProgress(scrubFraction);
+ mOverviewEventSender.getProxy().onQuickScrubProgress(scrubFraction);
if (DEBUG_OVERVIEW_PROXY) {
Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction);
}
@@ -304,9 +308,9 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
mTranslation /= SWITCH_STICKINESS;
}
if (mIsVertical) {
- homeButton.getCurrentView().setTranslationY(mTranslation);
+ mHomeButtonView.setTranslationY(mTranslation);
} else {
- homeButton.getCurrentView().setTranslationX(mTranslation);
+ mHomeButtonView.setTranslationX(mTranslation);
}
}
}
@@ -314,7 +318,7 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
- endQuickScrub();
+ endQuickScrub(true /* animate */);
break;
}
return mDraggingActive || mQuickScrubActive;
@@ -346,17 +350,6 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
x2 = x1 + width / 2 - mTrackPadding;
}
mTrackRect.set(x1, y1, x2, y2);
-
- // Get the touch rect of the home button location
- View homeView = mNavigationBarView.getHomeButton().getCurrentView();
- if (homeView != null) {
- int[] globalHomePos = homeView.getLocationOnScreen();
- int[] globalNavBarPos = mNavigationBarView.getLocationOnScreen();
- int homeX = globalHomePos[0] - globalNavBarPos[0];
- int homeY = globalHomePos[1] - globalNavBarPos[1];
- mHomeButtonRect.set(homeX, homeY, homeX + homeView.getMeasuredWidth(),
- homeY + homeView.getMeasuredHeight());
- }
}
@Override
@@ -367,6 +360,11 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
@Override
public void setBarState(boolean isVertical, boolean isRTL) {
+ final boolean changed = (mIsVertical != isVertical) || (mIsRTL != isRTL);
+ if (changed) {
+ // End quickscrub if the state changes mid-transition
+ endQuickScrub(false /* animate */);
+ }
mIsVertical = isVertical;
mIsRTL = isRTL;
try {
@@ -380,10 +378,6 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
}
}
- boolean isQuickScrubEnabled() {
- return SystemProperties.getBoolean("persist.quickstep.scrub.enabled", false);
- }
-
private void startQuickScrub() {
if (!mQuickScrubActive) {
mQuickScrubActive = true;
@@ -402,7 +396,7 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
}
}
- private void endQuickScrub() {
+ private void endQuickScrub(boolean animate) {
mHandler.removeCallbacks(mLongPressRunnable);
if (mDraggingActive || mQuickScrubActive) {
mButtonAnimator.setIntValues((int) mTranslation, 0);
@@ -416,6 +410,9 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
} catch (RemoteException e) {
Log.e(TAG, "Failed to send end of quick scrub.", e);
}
+ if (!animate) {
+ mQuickScrubEndAnimator.end();
+ }
}
mDraggingActive = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 14387631f64d..2b5085389804 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -166,6 +166,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
private boolean mScreenBlankingCallbackCalled;
private Callback mCallback;
private boolean mWallpaperSupportsAmbientMode;
+ private boolean mScreenOn;
// Scrim blanking callbacks
private Choreographer.FrameCallback mPendingFrameCallback;
@@ -785,10 +786,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
// Setting power states can happen after we push out the frame. Make sure we
// stay fully opaque until the power state request reaches the lower levels.
+ final int delay = mScreenOn ? 16 : 500;
if (DEBUG) {
- Log.d(TAG, "Waiting for the screen to turn on...");
+ Log.d(TAG, "Fading out scrims with delay: " + delay);
}
- getHandler().postDelayed(mBlankingTransitionRunnable, 500);
+ getHandler().postDelayed(mBlankingTransitionRunnable, delay);
};
doOnTheNextFrame(mPendingFrameCallback);
}
@@ -904,6 +906,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
* Interrupts blanking transitions once the display notifies that it's already on.
*/
public void onScreenTurnedOn() {
+ mScreenOn = true;
final Handler handler = getHandler();
if (handler.hasCallbacks(mBlankingTransitionRunnable)) {
if (DEBUG) {
@@ -914,6 +917,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
}
}
+ public void onScreenTurnedOff() {
+ mScreenOn = false;
+ }
+
public interface Callback {
default void onStart() {
}
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 458518c41c3a..24920cba21f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -111,6 +111,7 @@ import android.view.IWindowManager;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
+import android.view.RemoteAnimationAdapter;
import android.view.ThreadedRenderer;
import android.view.View;
import android.view.ViewGroup;
@@ -2849,7 +2850,7 @@ public class StatusBar extends SystemUI implements DemoMode,
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
int result = ActivityManager.START_CANCELED;
ActivityOptions options = new ActivityOptions(getActivityOptions(
- null /* sourceNotification */));
+ null /* remoteAnimation */));
options.setDisallowEnterPictureInPictureWhileLaunching(
disallowEnterPictureInPictureWhileLaunching);
if (intent == KeyguardBottomAreaView.INSECURE_CAMERA_INTENT) {
@@ -4413,6 +4414,7 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void onScreenTurnedOff() {
mFalsingManager.onScreenOff();
+ mScrimController.onScreenTurnedOff();
// If we pulse in from AOD, we turn the screen off first. However, updatingIsKeyguard
// in that case destroys the HeadsUpManager state, so don't do it in that case.
if (!isPulsing()) {
@@ -5000,11 +5002,15 @@ public class StatusBar extends SystemUI implements DemoMode,
fillInIntent = new Intent().putExtra(Notification.EXTRA_REMOTE_INPUT_DRAFT,
remoteInputText.toString());
}
+ RemoteAnimationAdapter adapter = mActivityLaunchAnimator.getLaunchAnimation(
+ row);
try {
+ ActivityManager.getService().registerRemoteAnimationForNextActivityStart(
+ intent.getCreatorPackage(), adapter);
launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
- null, null, getActivityOptions(row));
+ null, null, getActivityOptions(adapter));
mActivityLaunchAnimator.setLaunchResult(launchResult);
- } catch (PendingIntent.CanceledException e) {
+ } catch (RemoteException | PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here.
// Just log the exception message.
Log.w(TAG, "Sending contentIntent failed: " + e);
@@ -5164,7 +5170,8 @@ public class StatusBar extends SystemUI implements DemoMode,
AsyncTask.execute(() -> {
int launchResult = TaskStackBuilder.create(mContext)
.addNextIntentWithParentStack(intent)
- .startActivities(getActivityOptions(row),
+ .startActivities(getActivityOptions(
+ mActivityLaunchAnimator.getLaunchAnimation(row)),
new UserHandle(UserHandle.getUserId(appUid)));
mActivityLaunchAnimator.setLaunchResult(launchResult);
if (shouldCollapse()) {
@@ -5299,7 +5306,7 @@ public class StatusBar extends SystemUI implements DemoMode,
}
try {
intent.send(null, 0, null, null, null, null, getActivityOptions(
- null /* sourceNotification */));
+ null /* animationAdapter */));
} catch (PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here.
// Just log the exception message.
@@ -5327,10 +5334,10 @@ public class StatusBar extends SystemUI implements DemoMode,
return true;
}
- protected Bundle getActivityOptions(ExpandableNotificationRow sourceNotification) {
+ protected Bundle getActivityOptions(@Nullable RemoteAnimationAdapter animationAdapter) {
ActivityOptions options;
- if (sourceNotification != null) {
- options = mActivityLaunchAnimator.getLaunchAnimation(sourceNotification);
+ if (animationAdapter != null) {
+ options = ActivityOptions.makeRemoteAnimation(animationAdapter);
} else {
options = ActivityOptions.makeBasic();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index c30f6339f8da..948f524bb188 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -106,6 +106,7 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D
mLp.gravity = Gravity.TOP;
mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
mLp.setTitle("StatusBar");
+ mLp.accessibilityTitle = mContext.getString(R.string.status_bar);
mLp.packageName = mContext.getPackageName();
mStatusBarView = statusBarView;
mBarHeight = barHeight;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index 1da50ad65d62..503a1b40bb0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -36,6 +36,7 @@ import com.android.systemui.statusbar.stack.ViewState;
public class StatusIconContainer extends AlphaOptimizedLinearLayout {
private static final String TAG = "StatusIconContainer";
+ private static final boolean DEBUG = false;
private static final int MAX_ICONS = 5;
private static final int MAX_DOTS = 3;
@@ -94,7 +95,7 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout {
int childCount = getChildCount();
// Underflow === don't show content until that index
int firstUnderflowIndex = -1;
- android.util.Log.d(TAG, "calculateIconTransitions: start=" + translationX);
+ if (DEBUG) android.util.Log.d(TAG, "calculateIconTransitions: start=" + translationX);
//TODO: Dots
for (int i = childCount - 1; i >= 0; i--) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 9d1c1e8b4b77..98bebec8511e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -52,6 +52,7 @@ import com.android.systemui.Dependency;
import com.android.systemui.OverviewProxyService;
import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonInterface;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
@@ -269,11 +270,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
if (doIt) {
// If there was a pending remote recents animation, then we need to
// cancel the animation now before we handle the button itself
- try {
- ActivityManager.getService().cancelRecentsAnimation();
- } catch (RemoteException e) {
- Log.e(TAG, "Could not cancel recents animation", e);
- }
+ ActivityManagerWrapper.getInstance().cancelRecentsAnimation();
sendEvent(KeyEvent.ACTION_UP, 0);
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 57fc03cb7308..790135fc03ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -4,27 +4,105 @@ import android.app.PendingIntent;
import android.app.RemoteInput;
import android.content.Context;
import android.content.Intent;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.RippleDrawable;
import android.os.Bundle;
+import android.text.Layout;
+import android.text.TextPaint;
+import android.text.method.TransformationMethod;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
+import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
-import android.widget.LinearLayout;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import java.text.BreakIterator;
+import java.util.Comparator;
+import java.util.PriorityQueue;
+
/** View which displays smart reply buttons in notifications. */
-public class SmartReplyView extends LinearLayout {
+public class SmartReplyView extends ViewGroup {
private static final String TAG = "SmartReplyView";
+ private static final int MEASURE_SPEC_ANY_WIDTH =
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+
+ private static final Comparator<View> DECREASING_MEASURED_WIDTH_WITHOUT_PADDING_COMPARATOR =
+ (v1, v2) -> ((v2.getMeasuredWidth() - v2.getPaddingLeft() - v2.getPaddingRight())
+ - (v1.getMeasuredWidth() - v1.getPaddingLeft() - v1.getPaddingRight()));
+
+ private static final int SQUEEZE_FAILED = -1;
+
private final SmartReplyConstants mConstants;
+ /** Spacing to be applied between views. */
+ private final int mSpacing;
+
+ /** Horizontal padding of smart reply buttons if all of them use only one line of text. */
+ private final int mSingleLineButtonPaddingHorizontal;
+
+ /** Horizontal padding of smart reply buttons if at least one of them uses two lines of text. */
+ private final int mDoubleLineButtonPaddingHorizontal;
+
+ /** Increase in width of a smart reply button as a result of using two lines instead of one. */
+ private final int mSingleToDoubleLineButtonWidthIncrease;
+
+ private final BreakIterator mBreakIterator;
+
+ private PriorityQueue<Button> mCandidateButtonQueueForSqueezing;
+
public SmartReplyView(Context context, AttributeSet attrs) {
super(context, attrs);
mConstants = Dependency.get(SmartReplyConstants.class);
+
+ int spacing = 0;
+ int singleLineButtonPaddingHorizontal = 0;
+ int doubleLineButtonPaddingHorizontal = 0;
+
+ final TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.SmartReplyView,
+ 0, 0);
+ final int length = arr.getIndexCount();
+ for (int i = 0; i < length; i++) {
+ int attr = arr.getIndex(i);
+ switch (attr) {
+ case R.styleable.SmartReplyView_spacing:
+ spacing = arr.getDimensionPixelSize(i, 0);
+ break;
+ case R.styleable.SmartReplyView_singleLineButtonPaddingHorizontal:
+ singleLineButtonPaddingHorizontal = arr.getDimensionPixelSize(i, 0);
+ break;
+ case R.styleable.SmartReplyView_doubleLineButtonPaddingHorizontal:
+ doubleLineButtonPaddingHorizontal = arr.getDimensionPixelSize(i, 0);
+ break;
+ }
+ }
+ arr.recycle();
+
+ mSpacing = spacing;
+ mSingleLineButtonPaddingHorizontal = singleLineButtonPaddingHorizontal;
+ mDoubleLineButtonPaddingHorizontal = doubleLineButtonPaddingHorizontal;
+ mSingleToDoubleLineButtonWidthIncrease =
+ 2 * (doubleLineButtonPaddingHorizontal - singleLineButtonPaddingHorizontal);
+
+ mBreakIterator = BreakIterator.getLineInstance();
+ reallocateCandidateButtonQueueForSqueezing();
+ }
+
+ private void reallocateCandidateButtonQueueForSqueezing() {
+ // Instead of clearing the priority queue, we re-allocate so that it would fit all buttons
+ // exactly. This avoids (1) wasting memory because PriorityQueue never shrinks and
+ // (2) growing in onMeasure.
+ // The constructor throws an IllegalArgument exception if initial capacity is less than 1.
+ mCandidateButtonQueueForSqueezing = new PriorityQueue<>(
+ Math.max(getChildCount(), 1), DECREASING_MEASURED_WIDTH_WITHOUT_PADDING_COMPARATOR);
}
public void setRepliesFromRemoteInput(RemoteInput remoteInput, PendingIntent pendingIntent) {
@@ -39,6 +117,7 @@ public class SmartReplyView extends LinearLayout {
}
}
}
+ reallocateCandidateButtonQueueForSqueezing();
}
public static SmartReplyView inflate(Context context, ViewGroup root) {
@@ -46,7 +125,8 @@ public class SmartReplyView extends LinearLayout {
LayoutInflater.from(context).inflate(R.layout.smart_reply_view, root, false);
}
- private static Button inflateReplyButton(Context context, ViewGroup root, CharSequence choice,
+ @VisibleForTesting
+ static Button inflateReplyButton(Context context, ViewGroup root, CharSequence choice,
RemoteInput remoteInput, PendingIntent pendingIntent) {
Button b = (Button) LayoutInflater.from(context).inflate(
R.layout.smart_reply_button, root, false);
@@ -65,4 +145,376 @@ public class SmartReplyView extends LinearLayout {
});
return b;
}
+
+ @Override
+ public LayoutParams generateLayoutParams(AttributeSet attrs) {
+ return new LayoutParams(mContext, attrs);
+ }
+
+ @Override
+ protected LayoutParams generateDefaultLayoutParams() {
+ return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ }
+
+ @Override
+ protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams params) {
+ return new LayoutParams(params.width, params.height);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int targetWidth = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED
+ ? Integer.MAX_VALUE : MeasureSpec.getSize(widthMeasureSpec);
+
+ // Mark all buttons as hidden and un-squeezed.
+ resetButtonsLayoutParams();
+
+ if (!mCandidateButtonQueueForSqueezing.isEmpty()) {
+ Log.wtf(TAG, "Single line button queue leaked between onMeasure calls");
+ mCandidateButtonQueueForSqueezing.clear();
+ }
+
+ int measuredWidth = mPaddingLeft + mPaddingRight;
+ int maxChildHeight = 0;
+ int displayedChildCount = 0;
+ int buttonPaddingHorizontal = mSingleLineButtonPaddingHorizontal;
+
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ if (child.getVisibility() != View.VISIBLE || !(child instanceof Button)) {
+ continue;
+ }
+
+ child.setPadding(buttonPaddingHorizontal, child.getPaddingTop(),
+ buttonPaddingHorizontal, child.getPaddingBottom());
+ child.measure(MEASURE_SPEC_ANY_WIDTH, heightMeasureSpec);
+
+ final int lineCount = ((Button) child).getLineCount();
+ if (lineCount < 1 || lineCount > 2) {
+ // If smart reply has no text, or more than two lines, then don't show it.
+ continue;
+ }
+
+ if (lineCount == 1) {
+ mCandidateButtonQueueForSqueezing.add((Button) child);
+ }
+
+ // Remember the current measurements in case the current button doesn't fit in.
+ final int originalMaxChildHeight = maxChildHeight;
+ final int originalMeasuredWidth = measuredWidth;
+ final int originalButtonPaddingHorizontal = buttonPaddingHorizontal;
+
+ final int spacing = displayedChildCount == 0 ? 0 : mSpacing;
+ final int childWidth = child.getMeasuredWidth();
+ final int childHeight = child.getMeasuredHeight();
+ measuredWidth += spacing + childWidth;
+ maxChildHeight = Math.max(maxChildHeight, childHeight);
+
+ // Do we need to increase the number of lines in smart reply buttons to two?
+ final boolean increaseToTwoLines =
+ buttonPaddingHorizontal == mSingleLineButtonPaddingHorizontal
+ && (lineCount == 2 || measuredWidth > targetWidth);
+ if (increaseToTwoLines) {
+ measuredWidth += (displayedChildCount + 1) * mSingleToDoubleLineButtonWidthIncrease;
+ buttonPaddingHorizontal = mDoubleLineButtonPaddingHorizontal;
+ }
+
+ // If the last button doesn't fit into the remaining width, try squeezing preceding
+ // smart reply buttons.
+ if (measuredWidth > targetWidth) {
+ // Keep squeezing preceding and current smart reply buttons until they all fit.
+ while (measuredWidth > targetWidth
+ && !mCandidateButtonQueueForSqueezing.isEmpty()) {
+ final Button candidate = mCandidateButtonQueueForSqueezing.poll();
+ final int squeezeReduction = squeezeButton(candidate, heightMeasureSpec);
+ if (squeezeReduction != SQUEEZE_FAILED) {
+ maxChildHeight = Math.max(maxChildHeight, candidate.getMeasuredHeight());
+ measuredWidth -= squeezeReduction;
+ }
+ }
+
+ // If the current button still doesn't fit after squeezing all buttons, undo the
+ // last squeezing round.
+ if (measuredWidth > targetWidth) {
+ measuredWidth = originalMeasuredWidth;
+ maxChildHeight = originalMaxChildHeight;
+ buttonPaddingHorizontal = originalButtonPaddingHorizontal;
+
+ // Mark all buttons from the last squeezing round as "failed to squeeze", so
+ // that they're re-measured without squeezing later.
+ markButtonsWithPendingSqueezeStatusAs(LayoutParams.SQUEEZE_STATUS_FAILED, i);
+
+ // The current button doesn't fit, so there's no point in measuring further
+ // buttons.
+ break;
+ }
+
+ // The current button fits, so mark all squeezed buttons as "successfully squeezed"
+ // to prevent them from being un-squeezed in a subsequent squeezing round.
+ markButtonsWithPendingSqueezeStatusAs(LayoutParams.SQUEEZE_STATUS_SUCCESSFUL, i);
+ }
+
+ lp.show = true;
+ displayedChildCount++;
+ }
+
+ // We're done squeezing buttons, so we can clear the priority queue.
+ mCandidateButtonQueueForSqueezing.clear();
+
+ // Finally, we need to update corner radius and re-measure some buttons.
+ updateCornerRadiusAndRemeasureButtonsIfNecessary(buttonPaddingHorizontal, maxChildHeight);
+
+ setMeasuredDimension(
+ resolveSize(Math.max(getSuggestedMinimumWidth(), measuredWidth), widthMeasureSpec),
+ resolveSize(Math.max(getSuggestedMinimumHeight(),
+ mPaddingTop + maxChildHeight + mPaddingBottom), heightMeasureSpec));
+ }
+
+ private void resetButtonsLayoutParams() {
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ lp.show = false;
+ lp.squeezeStatus = LayoutParams.SQUEEZE_STATUS_NONE;
+ }
+ }
+
+ private int squeezeButton(Button button, int heightMeasureSpec) {
+ final int estimatedOptimalTextWidth = estimateOptimalSqueezedButtonTextWidth(button);
+ if (estimatedOptimalTextWidth == SQUEEZE_FAILED) {
+ return SQUEEZE_FAILED;
+ }
+ return squeezeButtonToTextWidth(button, heightMeasureSpec, estimatedOptimalTextWidth);
+ }
+
+ private int estimateOptimalSqueezedButtonTextWidth(Button button) {
+ // Find a line-break point in the middle of the smart reply button text.
+ final String rawText = button.getText().toString();
+
+ // The button sometimes has a transformation affecting text layout (e.g. all caps).
+ final TransformationMethod transformation = button.getTransformationMethod();
+ final String text = transformation == null ?
+ rawText : transformation.getTransformation(rawText, button).toString();
+ final int length = text.length();
+ mBreakIterator.setText(text);
+
+ if (mBreakIterator.preceding(length / 2) == BreakIterator.DONE) {
+ if (mBreakIterator.next() == BreakIterator.DONE) {
+ // Can't find a single possible line break in either direction.
+ return SQUEEZE_FAILED;
+ }
+ }
+
+ final TextPaint paint = button.getPaint();
+ final int initialPosition = mBreakIterator.current();
+ final float initialLeftTextWidth = Layout.getDesiredWidth(text, 0, initialPosition, paint);
+ final float initialRightTextWidth =
+ Layout.getDesiredWidth(text, initialPosition, length, paint);
+ float optimalTextWidth = Math.max(initialLeftTextWidth, initialRightTextWidth);
+
+ if (initialLeftTextWidth != initialRightTextWidth) {
+ // See if there's a better line-break point (leading to a more narrow button) in
+ // either left or right direction.
+ final boolean moveLeft = initialLeftTextWidth > initialRightTextWidth;
+ final int maxSqueezeRemeasureAttempts = mConstants.getMaxSqueezeRemeasureAttempts();
+ for (int i = 0; i < maxSqueezeRemeasureAttempts; i++) {
+ final int newPosition =
+ moveLeft ? mBreakIterator.previous() : mBreakIterator.next();
+ if (newPosition == BreakIterator.DONE) {
+ break;
+ }
+
+ final float newLeftTextWidth = Layout.getDesiredWidth(text, 0, newPosition, paint);
+ final float newRightTextWidth =
+ Layout.getDesiredWidth(text, newPosition, length, paint);
+ final float newOptimalTextWidth = Math.max(newLeftTextWidth, newRightTextWidth);
+ if (newOptimalTextWidth < optimalTextWidth) {
+ optimalTextWidth = newOptimalTextWidth;
+ } else {
+ break;
+ }
+
+ boolean tooFar = moveLeft
+ ? newLeftTextWidth <= newRightTextWidth
+ : newLeftTextWidth >= newRightTextWidth;
+ if (tooFar) {
+ break;
+ }
+ }
+ }
+
+ return (int) Math.ceil(optimalTextWidth);
+ }
+
+ private int squeezeButtonToTextWidth(Button button, int heightMeasureSpec, int textWidth) {
+ int oldWidth = button.getMeasuredWidth();
+ if (button.getPaddingLeft() != mDoubleLineButtonPaddingHorizontal) {
+ // Correct for the fact that the button was laid out with single-line horizontal
+ // padding.
+ oldWidth += mSingleToDoubleLineButtonWidthIncrease;
+ }
+
+ // Re-measure the squeezed smart reply button.
+ button.setPadding(mDoubleLineButtonPaddingHorizontal, button.getPaddingTop(),
+ mDoubleLineButtonPaddingHorizontal, button.getPaddingBottom());
+ final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(
+ 2 * mDoubleLineButtonPaddingHorizontal + textWidth, MeasureSpec.AT_MOST);
+ button.measure(widthMeasureSpec, heightMeasureSpec);
+
+ final int newWidth = button.getMeasuredWidth();
+
+ final LayoutParams lp = (LayoutParams) button.getLayoutParams();
+ if (button.getLineCount() > 2 || newWidth >= oldWidth) {
+ lp.squeezeStatus = LayoutParams.SQUEEZE_STATUS_FAILED;
+ return SQUEEZE_FAILED;
+ } else {
+ lp.squeezeStatus = LayoutParams.SQUEEZE_STATUS_PENDING;
+ return oldWidth - newWidth;
+ }
+ }
+
+ private void updateCornerRadiusAndRemeasureButtonsIfNecessary(
+ int buttonPaddingHorizontal, int maxChildHeight) {
+ final float cornerRadius = ((float) maxChildHeight) / 2;
+ final int maxChildHeightMeasure =
+ MeasureSpec.makeMeasureSpec(maxChildHeight, MeasureSpec.EXACTLY);
+
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ if (!lp.show) {
+ continue;
+ }
+
+ // Update corner radius.
+ GradientDrawable backgroundDrawable =
+ (GradientDrawable) ((RippleDrawable) child.getBackground()).getDrawable(0);
+ backgroundDrawable.setCornerRadius(cornerRadius);
+
+ boolean requiresNewMeasure = false;
+ int newWidth = child.getMeasuredWidth();
+
+ // Re-measure reason 1: The button needs to be un-squeezed (either because it resulted
+ // in more than two lines or because it was unnecessary).
+ if (lp.squeezeStatus == LayoutParams.SQUEEZE_STATUS_FAILED) {
+ requiresNewMeasure = true;
+ newWidth = Integer.MAX_VALUE;
+ }
+
+ // Re-measure reason 2: The button's horizontal padding is incorrect (because it was
+ // measured with the wrong number of lines).
+ if (child.getPaddingLeft() != buttonPaddingHorizontal) {
+ requiresNewMeasure = true;
+ if (buttonPaddingHorizontal == mSingleLineButtonPaddingHorizontal) {
+ // Decrease padding (2->1 line).
+ newWidth -= mSingleToDoubleLineButtonWidthIncrease;
+ } else {
+ // Increase padding (1->2 lines).
+ newWidth += mSingleToDoubleLineButtonWidthIncrease;
+ }
+ child.setPadding(buttonPaddingHorizontal, child.getPaddingTop(),
+ buttonPaddingHorizontal, child.getPaddingBottom());
+ }
+
+ // Re-measure reason 3: The button's height is less than the max height of all buttons
+ // (all should have the same height).
+ if (child.getMeasuredHeight() != maxChildHeight) {
+ requiresNewMeasure = true;
+ }
+
+ if (requiresNewMeasure) {
+ child.measure(MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.AT_MOST),
+ maxChildHeightMeasure);
+ }
+ }
+ }
+
+ private void markButtonsWithPendingSqueezeStatusAs(int squeezeStatus, int maxChildIndex) {
+ for (int i = 0; i <= maxChildIndex; i++) {
+ final View child = getChildAt(i);
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ if (lp.squeezeStatus == LayoutParams.SQUEEZE_STATUS_PENDING) {
+ lp.squeezeStatus = squeezeStatus;
+ }
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ final boolean isRtl = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+
+ final int width = right - left;
+ int position = isRtl ? width - mPaddingRight : mPaddingLeft;
+
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ if (!lp.show) {
+ continue;
+ }
+
+ final int childWidth = child.getMeasuredWidth();
+ final int childHeight = child.getMeasuredHeight();
+ final int childLeft = isRtl ? position - childWidth : position;
+ child.layout(childLeft, 0, childLeft + childWidth, childHeight);
+
+ final int childWidthWithSpacing = childWidth + mSpacing;
+ if (isRtl) {
+ position -= childWidthWithSpacing;
+ } else {
+ position += childWidthWithSpacing;
+ }
+ }
+ }
+
+ @Override
+ protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ return lp.show && super.drawChild(canvas, child, drawingTime);
+ }
+
+ @VisibleForTesting
+ static class LayoutParams extends ViewGroup.LayoutParams {
+
+ /** Button is not squeezed. */
+ private static final int SQUEEZE_STATUS_NONE = 0;
+
+ /**
+ * Button was successfully squeezed, but it might be un-squeezed later if the squeezing
+ * turns out to have been unnecessary (because there's still not enough space to add another
+ * button).
+ */
+ private static final int SQUEEZE_STATUS_PENDING = 1;
+
+ /** Button was successfully squeezed and it won't be un-squeezed. */
+ private static final int SQUEEZE_STATUS_SUCCESSFUL = 2;
+
+ /**
+ * Button wasn't successfully squeezed. The squeezing resulted in more than two lines of
+ * text or it didn't reduce the button's width at all. The button will have to be
+ * re-measured to use only one line of text.
+ */
+ private static final int SQUEEZE_STATUS_FAILED = 3;
+
+ private boolean show = false;
+ private int squeezeStatus = SQUEEZE_STATUS_NONE;
+
+ private LayoutParams(Context c, AttributeSet attrs) {
+ super(c, attrs);
+ }
+
+ private LayoutParams(int width, int height) {
+ super(width, height);
+ }
+
+ @VisibleForTesting
+ boolean isShown() {
+ return show;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
index 45abd456ea16..eb0c89b06528 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
@@ -18,7 +18,7 @@ import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_CODE_END;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_CODE_START;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_IMAGE_DELIM;
-import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.MENU_IME;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.MENU_IME_ROTATE;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAVSPACE;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAV_BAR_LEFT;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAV_BAR_RIGHT;
@@ -29,24 +29,14 @@ import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.ext
import android.annotation.Nullable;
import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.content.res.Resources;
import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Paint.FontMetricsInt;
-import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.Handler;
-import android.support.v14.preference.PreferenceFragment;
-import android.support.v7.preference.DropDownPreference;
import android.support.v7.preference.ListPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
-import android.support.v7.preference.Preference.OnPreferenceClickListener;
-import android.support.v7.preference.PreferenceCategory;
import android.text.SpannableStringBuilder;
import android.text.style.ImageSpan;
import android.util.Log;
@@ -56,7 +46,6 @@ import android.widget.EditText;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.NavigationBarInflaterView;
import com.android.systemui.tuner.TunerService.Tunable;
import java.util.ArrayList;
@@ -100,7 +89,7 @@ public class NavBarTuner extends TunerPreferenceFragment {
addPreferencesFromResource(R.xml.nav_bar_tuner);
bindLayout((ListPreference) findPreference(LAYOUT));
bindButton(NAV_BAR_LEFT, NAVSPACE, LEFT);
- bindButton(NAV_BAR_RIGHT, MENU_IME, RIGHT);
+ bindButton(NAV_BAR_RIGHT, MENU_IME_ROTATE, RIGHT);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index 0c3637d6e234..58abf19dd238 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -14,16 +14,27 @@
package com.android.systemui.statusbar.policy;
+import static android.view.View.MeasureSpec;
+
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Resources;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
@@ -34,30 +45,40 @@ import org.junit.runner.RunWith;
@TestableLooper.RunWithLooper
@SmallTest
public class SmartReplyViewTest extends SysuiTestCase {
-
private static final String TEST_RESULT_KEY = "test_result_key";
private static final String TEST_ACTION = "com.android.ACTION";
+
private static final String[] TEST_CHOICES = new String[]{"Hello", "What's up?", "I'm here"};
+ private static final int WIDTH_SPEC = MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY);
+ private static final int HEIGHT_SPEC = MeasureSpec.makeMeasureSpec(400, MeasureSpec.AT_MOST);
+
private BlockingQueueIntentReceiver mReceiver;
private SmartReplyView mView;
+ private int mSingleLinePaddingHorizontal;
+ private int mDoubleLinePaddingHorizontal;
+ private int mSpacing;
+
@Before
public void setUp() {
mReceiver = new BlockingQueueIntentReceiver();
mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION));
mView = SmartReplyView.inflate(mContext, null);
+
+
+ final Resources res = mContext.getResources();
+ mSingleLinePaddingHorizontal = res.getDimensionPixelSize(
+ R.dimen.smart_reply_button_padding_horizontal_single_line);
+ mDoubleLinePaddingHorizontal = res.getDimensionPixelSize(
+ R.dimen.smart_reply_button_padding_horizontal_double_line);
+ mSpacing = res.getDimensionPixelSize(R.dimen.smart_reply_button_spacing);
}
@Test
public void testSendSmartReply_intentContainsResultsAndSource() throws InterruptedException {
- PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
- new Intent(TEST_ACTION), 0);
- RemoteInput input = new RemoteInput.Builder(TEST_RESULT_KEY).setChoices(
- TEST_CHOICES).build();
-
- mView.setRepliesFromRemoteInput(input, pendingIntent);
+ setRepliesFromRemoteInput(TEST_CHOICES);
mView.getChildAt(2).performClick();
@@ -66,4 +87,259 @@ public class SmartReplyViewTest extends SysuiTestCase {
RemoteInput.getResultsFromIntent(resultIntent).get(TEST_RESULT_KEY));
assertEquals(RemoteInput.SOURCE_CHOICE, RemoteInput.getResultsSource(resultIntent));
}
+
+ @Test
+ public void testMeasure_empty() {
+ mView.measure(WIDTH_SPEC, HEIGHT_SPEC);
+ assertEquals(500, mView.getMeasuredWidthAndState());
+ assertEquals(0, mView.getMeasuredHeightAndState());
+ }
+
+ @Test
+ public void testLayout_empty() {
+ mView.measure(WIDTH_SPEC, HEIGHT_SPEC);
+ mView.layout(0, 0, 500, 0);
+ }
+
+
+ // Instead of manually calculating the expected measurement/layout results, we build the
+ // expectations as ordinary linear layouts and then check that the relevant parameters in the
+ // corresponding SmartReplyView and LinearView are equal.
+
+ @Test
+ public void testMeasure_shortChoices() {
+ final CharSequence[] choices = new CharSequence[]{"Hi", "Hello", "Bye"};
+
+ // All choices should be displayed as SINGLE-line smart reply buttons.
+ ViewGroup expectedView = buildExpectedView(choices, 1);
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+ setRepliesFromRemoteInput(choices);
+ mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+ assertEqualMeasures(expectedView, mView);
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(2));
+ }
+
+ @Test
+ public void testLayout_shortChoices() {
+ final CharSequence[] choices = new CharSequence[]{"Hi", "Hello", "Bye"};
+
+ // All choices should be displayed as SINGLE-line smart reply buttons.
+ ViewGroup expectedView = buildExpectedView(choices, 1);
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ expectedView.layout(10, 10, 10 + expectedView.getMeasuredWidth(),
+ 10 + expectedView.getMeasuredHeight());
+
+ setRepliesFromRemoteInput(choices);
+ mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ mView.layout(10, 10, 10 + mView.getMeasuredWidth(), 10 + mView.getMeasuredHeight());
+
+ assertEqualLayouts(expectedView, mView);
+ assertEqualLayouts(expectedView.getChildAt(0), mView.getChildAt(0));
+ assertEqualLayouts(expectedView.getChildAt(1), mView.getChildAt(1));
+ assertEqualLayouts(expectedView.getChildAt(2), mView.getChildAt(2));
+ }
+
+ @Test
+ public void testMeasure_choiceWithTwoLines() {
+ final CharSequence[] choices = new CharSequence[]{"Hi", "Hello\neveryone", "Bye"};
+
+ // All choices should be displayed as DOUBLE-line smart reply buttons.
+ ViewGroup expectedView = buildExpectedView(choices, 2);
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+ setRepliesFromRemoteInput(choices);
+ mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+ assertEqualMeasures(expectedView, mView);
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(2));
+ }
+
+ @Test
+ public void testLayout_choiceWithTwoLines() {
+ final CharSequence[] choices = new CharSequence[]{"Hi", "Hello\neveryone", "Bye"};
+
+ // All choices should be displayed as DOUBLE-line smart reply buttons.
+ ViewGroup expectedView = buildExpectedView(choices, 2);
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ expectedView.layout(10, 10, 10 + expectedView.getMeasuredWidth(),
+ 10 + expectedView.getMeasuredHeight());
+
+ setRepliesFromRemoteInput(choices);
+ mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ mView.layout(10, 10, 10 + mView.getMeasuredWidth(), 10 + mView.getMeasuredHeight());
+
+ assertEqualLayouts(expectedView, mView);
+ assertEqualLayouts(expectedView.getChildAt(0), mView.getChildAt(0));
+ assertEqualLayouts(expectedView.getChildAt(1), mView.getChildAt(1));
+ assertEqualLayouts(expectedView.getChildAt(2), mView.getChildAt(2));
+ }
+
+ @Test
+ public void testMeasure_choiceWithThreeLines() {
+ final CharSequence[] choices = new CharSequence[]{"Hi", "Hello\nevery\nbody", "Bye"};
+
+ // The choice with three lines should NOT be displayed. All other choices should be
+ // displayed as SINGLE-line smart reply buttons.
+ ViewGroup expectedView = buildExpectedView(new CharSequence[]{"Hi", "Bye"}, 1);
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+ setRepliesFromRemoteInput(choices);
+ mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+ assertEqualMeasures(expectedView, mView);
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0));
+ assertReplyButtonHidden(mView.getChildAt(1));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(2));
+ }
+
+ @Test
+ public void testLayout_choiceWithThreeLines() {
+ final CharSequence[] choices = new CharSequence[]{"Hi", "Hello\nevery\nbody", "Bye"};
+
+ // The choice with three lines should NOT be displayed. All other choices should be
+ // displayed as SINGLE-line smart reply buttons.
+ ViewGroup expectedView = buildExpectedView(new CharSequence[]{"Hi", "Bye"}, 1);
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ expectedView.layout(10, 10, 10 + expectedView.getMeasuredWidth(),
+ 10 + expectedView.getMeasuredHeight());
+
+ setRepliesFromRemoteInput(choices);
+ mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ mView.layout(10, 10, 10 + mView.getMeasuredWidth(), 10 + mView.getMeasuredHeight());
+
+ assertEqualLayouts(expectedView, mView);
+ assertEqualLayouts(expectedView.getChildAt(0), mView.getChildAt(0));
+ // We don't care about mView.getChildAt(1)'s layout because it's hidden (see
+ // testMeasure_choiceWithThreeLines).
+ assertEqualLayouts(expectedView.getChildAt(1), mView.getChildAt(2));
+ }
+
+ @Test
+ public void testMeasure_squeezeLongest() {
+ final CharSequence[] choices = new CharSequence[]{"Short", "Short", "Looooooong replyyyyy"};
+
+ // All choices should be displayed as DOUBLE-line smart reply buttons.
+ ViewGroup expectedView = buildExpectedView(
+ new CharSequence[]{"Short", "Short", "Looooooong \nreplyyyyy"}, 2);
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+ setRepliesFromRemoteInput(choices);
+ mView.measure(
+ MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST),
+ MeasureSpec.UNSPECIFIED);
+
+ assertEqualMeasures(expectedView, mView);
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(2));
+ }
+
+ @Test
+ public void testLayout_squeezeLongest() {
+ final CharSequence[] choices = new CharSequence[]{"Short", "Short", "Looooooong replyyyyy"};
+
+ // All choices should be displayed as DOUBLE-line smart reply buttons.
+ ViewGroup expectedView = buildExpectedView(
+ new CharSequence[]{"Short", "Short", "Looooooong \nreplyyyyy"}, 2);
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ expectedView.layout(10, 10, 10 + expectedView.getMeasuredWidth(),
+ 10 + expectedView.getMeasuredHeight());
+
+ setRepliesFromRemoteInput(choices);
+ mView.measure(
+ MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST),
+ MeasureSpec.UNSPECIFIED);
+ mView.layout(10, 10, 10 + mView.getMeasuredWidth(), 10 + mView.getMeasuredHeight());
+
+ assertEqualLayouts(expectedView, mView);
+ assertEqualLayouts(expectedView.getChildAt(0), mView.getChildAt(0));
+ assertEqualLayouts(expectedView.getChildAt(1), mView.getChildAt(1));
+ assertEqualLayouts(expectedView.getChildAt(2), mView.getChildAt(2));
+ }
+
+ private void setRepliesFromRemoteInput(CharSequence[] choices) {
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
+ new Intent(TEST_ACTION), 0);
+ RemoteInput input = new RemoteInput.Builder(TEST_RESULT_KEY).setChoices(choices).build();
+ mView.setRepliesFromRemoteInput(input, pendingIntent);
+ }
+
+ /** Builds a {@link ViewGroup} whose measures and layout mirror a {@link SmartReplyView}. */
+ private ViewGroup buildExpectedView(CharSequence[] choices, int lineCount) {
+ LinearLayout layout = new LinearLayout(mContext);
+ layout.setOrientation(LinearLayout.HORIZONTAL);
+
+ // Baseline alignment causes expected heights to be off by one or two pixels on some
+ // devices.
+ layout.setBaselineAligned(false);
+
+ final boolean isRtl = mView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+ final int paddingHorizontal;
+ switch (lineCount) {
+ case 1:
+ paddingHorizontal = mSingleLinePaddingHorizontal;
+ break;
+ case 2:
+ paddingHorizontal = mDoubleLinePaddingHorizontal;
+ break;
+ default:
+ fail("Invalid line count " + lineCount);
+ return null;
+ }
+
+ Button previous = null;
+ for (CharSequence choice : choices) {
+ Button current = SmartReplyView.inflateReplyButton(mContext, mView, choice, null, null);
+ current.setPadding(paddingHorizontal, current.getPaddingTop(), paddingHorizontal,
+ current.getPaddingBottom());
+ if (previous != null) {
+ ViewGroup.MarginLayoutParams lp =
+ (ViewGroup.MarginLayoutParams) previous.getLayoutParams();
+ if (isRtl) {
+ lp.leftMargin = mSpacing;
+ } else {
+ lp.rightMargin = mSpacing;
+ }
+ }
+ layout.addView(current);
+ previous = current;
+ }
+
+ return layout;
+ }
+
+ private static void assertEqualMeasures(View expected, View actual) {
+ assertEquals(expected.getMeasuredWidth(), actual.getMeasuredWidth());
+ assertEquals(expected.getMeasuredHeight(), actual.getMeasuredHeight());
+ }
+
+ private static void assertReplyButtonShownWithEqualMeasures(View expected, View actual) {
+ assertReplyButtonShown(actual);
+ assertEqualMeasures(expected, actual);
+ assertEquals(expected.getPaddingLeft(), actual.getPaddingLeft());
+ assertEquals(expected.getPaddingTop(), actual.getPaddingTop());
+ assertEquals(expected.getPaddingRight(), actual.getPaddingRight());
+ assertEquals(expected.getPaddingBottom(), actual.getPaddingBottom());
+ }
+
+ private static void assertReplyButtonShown(View view) {
+ assertTrue(((SmartReplyView.LayoutParams) view.getLayoutParams()).isShown());
+ }
+
+ private static void assertReplyButtonHidden(View view) {
+ assertFalse(((SmartReplyView.LayoutParams) view.getLayoutParams()).isShown());
+ }
+
+ private static void assertEqualLayouts(View expected, View actual) {
+ assertEquals(expected.getLeft(), actual.getLeft());
+ assertEquals(expected.getTop(), actual.getTop());
+ assertEquals(expected.getRight(), actual.getRight());
+ assertEquals(expected.getBottom(), actual.getBottom());
+ }
}
diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/AndroidManifest.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/AndroidManifest.xml
index 71ce6b433215..426aae969fd4 100644
--- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/AndroidManifest.xml
+++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/AndroidManifest.xml
@@ -2,7 +2,9 @@
package="com.android.internal.display.cutout.emulation.narrow"
android:versionCode="1"
android:versionName="1.0">
- <overlay android:targetPackage="android" android:priority="1"/>
+ <overlay android:targetPackage="android"
+ android:category="com.android.internal.display_cutout_emulation"
+ android:priority="1"/>
<application android:label="@string/display_cutout_emulation_overlay" android:hasCode="false"/>
</manifest>
diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/AndroidManifest.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/AndroidManifest.xml
index 5a93cfb06c6d..368a2d5c17eb 100644
--- a/packages/overlays/DisplayCutoutEmulationTallOverlay/AndroidManifest.xml
+++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/AndroidManifest.xml
@@ -18,7 +18,9 @@
package="com.android.internal.display.cutout.emulation.tall"
android:versionCode="1"
android:versionName="1.0">
- <overlay android:targetPackage="android" android:priority="1"/>
+ <overlay android:targetPackage="android"
+ android:category="com.android.internal.display_cutout_emulation"
+ android:priority="1"/>
<application android:label="@string/display_cutout_emulation_overlay" android:hasCode="false"/>
</manifest>
diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/AndroidManifest.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/AndroidManifest.xml
index 96bd06028611..b721efe8a795 100644
--- a/packages/overlays/DisplayCutoutEmulationWideOverlay/AndroidManifest.xml
+++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/AndroidManifest.xml
@@ -18,7 +18,9 @@
package="com.android.internal.display.cutout.emulation.wide"
android:versionCode="1"
android:versionName="1.0">
- <overlay android:targetPackage="android" android:priority="1"/>
+ <overlay android:targetPackage="android"
+ android:category="com.android.internal.display_cutout_emulation"
+ android:priority="1"/>
<application android:label="@string/display_cutout_emulation_overlay" android:hasCode="false"/>
</manifest>
diff --git a/pathmap.mk b/pathmap.mk
index c241d9978316..8b77e62860b8 100644
--- a/pathmap.mk
+++ b/pathmap.mk
@@ -20,11 +20,6 @@
# directories, despite the fact that it was historically used for that!
#
-# Import path mappings from the support library project. This will set up
-# FRAMEWORKS_SUPPORT_JAVA_SRC_DIRS and FRAMEWORKS_SUPPORT_JAVA_LIBRARIES for
-# use later in this file.
-include $(LOCAL_PATH)/../support/pathmap.mk
-
#
# A list of all source roots under frameworks/multidex.
#
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index ae5e133fa02f..e118c4999712 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3985,6 +3985,8 @@ message MetricsEvent {
// Package: Package of app that was autofilled
// Tag FIELD_AUTOFILL_FILTERTEXT_LEN: The length of the filter text
// Tag FIELD_AUTOFILL_NUM_DATASETS: The number of datasets shown
+ // NOTE: starting on OS P, it also added the following field:
+ // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
AUTOFILL_FILL_UI = 910;
// Tag of a field for the length of the filter text
@@ -4011,7 +4013,9 @@ message MetricsEvent {
// Type TYPE_CLOSE: UI was destroyed without influence of the user
// Type TYPE_ACTION: data was saved
// Package: Package of app that was autofilled
- // Tag FIELD_AUTOFILL_NUM_ID: The number of ids that are saved
+ // Tag FIELD_AUTOFILL_NUM_IDS: The number of ids that are saved
+ // NOTE: starting on OS P, it also added the following field:
+ // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
AUTOFILL_SAVE_UI = 916;
// Tag of a field for the number of saveable ids
@@ -5083,7 +5087,8 @@ message MetricsEvent {
// An autofill service updated its user data
// Package: Package of the autofill service that updated the user data
- // Counter: number of fields added (or 0 if reset)
+ // Tag FIELD_AUTOFILL_NUM_VALUES: number of fields added (or 0 if reset)
+ // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
// OS: P
AUTOFILL_USERDATA_UPDATED = 1272;
@@ -5171,7 +5176,6 @@ message MetricsEvent {
// An autofill service was bound using an unofficial(but still supported) permission.
// Package: Package of the autofill service
// OS: P
-
AUTOFILL_INVALID_PERMISSION = 1289;
// OPEN: QS Alarm tile shown
@@ -5213,6 +5217,67 @@ message MetricsEvent {
// OS: P
ACTION_OUTPUT_CHOOSER_DISCONNECT = 1297;
+ // OPEN: TV Settings > Home theater control
+ // OS: P
+ SETTINGS_TV_HOME_THEATER_CONTROL_CATEGORY = 1298;
+
+ // OPEN: TV Settings > TV Inputs (Inputs & Devices)
+ // OS: P
+ SETTINGS_TV_INPUTS_CATEGORY = 1299;
+
+ // OPEN: TV Settings > Device
+ // OS: P
+ SETTINGS_TV_DEVICE_CATEGORY = 1300;
+
+ // OPEN: TV Settings > Network > Proxy settings
+ // OS: P
+ DIALOG_TV_NETWORK_PROXY = 1301;
+
+ // Events for battery saver turning on/off and/or the interactive state changes.
+ // OS: P
+ BATTERY_SAVER = 1302;
+
+ // Device interactive state -- i.e. the screen ON (=1) or OFF (=1)
+ // OS: P
+ FIELD_INTERACTIVE = 1303;
+
+ // Time spent in milliseconds in the current mode.
+ // OS: P
+ FIELD_DURATION_MILLIS = 1304;
+
+ // Battery level in uA (0 - ~3,000,000 depending on device) when the current "mode" started.
+ // OS: P
+ FIELD_START_BATTERY_UA = 1305;
+
+ // Battery level in uA (0 - ~3,000,000 depending on device) when this event was created.
+ // OS: P
+ FIELD_END_BATTERY_UA = 1306;
+
+ // Battery level in % (0-100) when the current "mode" started.
+ // OS: P
+ FIELD_START_BATTERY_PERCENT = 1307;
+
+ // Battery level in % (0-100) when this event was created.
+ // OS: P
+ FIELD_END_BATTERY_PERCENT = 1308;
+
+ // ACTION: Settings > Display > Night Light
+ // SUBTYPE: com.android.server.display.ColorDisplayService.AutoMode value
+ // CATEGORY: SETTINGS
+ // OS: P
+ ACTION_NIGHT_DISPLAY_AUTO_MODE_CHANGED = 1309;
+
+ // ACTION: Settings > Display > Night Light
+ // CATEGORY: SETTINGS
+ // SUBTYPE: 0 is starting time, 1 is ending time
+ // OS: P
+ ACTION_NIGHT_DISPLAY_AUTO_MODE_CUSTOM_TIME_CHANGED = 1310;
+
+ // FIELD: Current mode corresponding to a QS tile
+ // CATEGORY: QUICK SETTINGS
+ // OS: P
+ FIELD_QS_MODE = 1311;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index 08fdb9775d0a..608970f59a66 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -204,6 +204,10 @@ message SystemMessage {
// Package: android
NOTE_USB_TETHER = 47;
+ // Inform that DND settings have changed on OS upgrade
+ // Package: android
+ NOTE_ZEN_UPGRADE = 48;
+
// ADD_NEW_IDS_ABOVE_THIS_LINE
// Legacy IDs with arbitrary values appear below
// Legacy IDs existed as stable non-conflicting constants prior to the O release
@@ -253,6 +257,7 @@ message SystemMessage {
// Notify the user about public volume state changes..
// Package: com.android.systemui
+
NOTE_STORAGE_PUBLIC = 0x53505542; // 1397773634
// Notify the user about private volume state changes.
diff --git a/rs/OWNERS b/rs/OWNERS
new file mode 100644
index 000000000000..61853d3d40cf
--- /dev/null
+++ b/rs/OWNERS
@@ -0,0 +1,5 @@
+butlermichael@google.com
+dgross@google.com
+jeanluc@google.com
+miaowang@google.com
+yangni@google.com
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index c36bb6d2e096..5b5d18f4aaf7 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -446,8 +446,10 @@ class MagnificationController implements Handler.Callback {
mMagnificationRegion.getBounds(viewport);
final MagnificationSpec spec = mCurrentMagnificationSpec;
final float oldScale = spec.scale;
- final float oldCenterX = (viewport.width() / 2.0f - spec.offsetX) / oldScale;
- final float oldCenterY = (viewport.height() / 2.0f - spec.offsetY) / oldScale;
+ final float oldCenterX
+ = (viewport.width() / 2.0f - spec.offsetX + viewport.left) / oldScale;
+ final float oldCenterY
+ = (viewport.height() / 2.0f - spec.offsetY + viewport.top) / oldScale;
final float normPivotX = (pivotX - spec.offsetX) / oldScale;
final float normPivotY = (pivotY - spec.offsetY) / oldScale;
final float offsetX = (oldCenterX - normPivotX) * (oldScale / scale);
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 52ab85c480b3..6c6dd5b8bd67 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -402,9 +402,9 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
com.android.internal.R.dimen.config_screen_magnification_scaling_threshold,
scaleValue, false);
mScalingThreshold = scaleValue.getFloat();
- mScaleGestureDetector = new ScaleGestureDetector(context, this);
+ mScaleGestureDetector = new ScaleGestureDetector(context, this, Handler.getMain());
mScaleGestureDetector.setQuickScaleEnabled(false);
- mScrollGestureDetector = new GestureDetector(context, this);
+ mScrollGestureDetector = new GestureDetector(context, this, Handler.getMain());
}
@Override
@@ -638,7 +638,7 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
@VisibleForTesting boolean mShortcutTriggered;
- @VisibleForTesting Handler mHandler = new Handler(this);
+ @VisibleForTesting Handler mHandler = new Handler(Looper.getMainLooper(), this);
public DetectingState(Context context) {
mLongTapMinDelay = ViewConfiguration.getLongPressTimeout();
@@ -654,7 +654,9 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
final int type = message.what;
switch (type) {
case MESSAGE_ON_TRIPLE_TAP_AND_HOLD: {
- onTripleTapAndHold(/* down */ (MotionEvent) message.obj);
+ MotionEvent down = (MotionEvent) message.obj;
+ transitionToViewportDraggingStateAndClear(down);
+ down.recycle();
}
break;
case MESSAGE_TRANSITION_TO_DELEGATING_STATE: {
@@ -720,8 +722,7 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
// over insta-delegating on 3tap&swipe
// (which is a rare combo to be used aside from magnification)
if (isMultiTapTriggered(2 /* taps */)) {
- transitionTo(mViewportDraggingState);
- clear();
+ transitionToViewportDraggingStateAndClear(event);
} else {
transitionToDelegatingStateAndClear();
}
@@ -806,7 +807,8 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
/** -> {@link ViewportDraggingState} */
public void afterLongTapTimeoutTransitionToDraggingState(MotionEvent event) {
mHandler.sendMessageDelayed(
- mHandler.obtainMessage(MESSAGE_ON_TRIPLE_TAP_AND_HOLD, event),
+ mHandler.obtainMessage(MESSAGE_ON_TRIPLE_TAP_AND_HOLD,
+ MotionEvent.obtain(event)),
ViewConfiguration.getLongPressTimeout());
}
@@ -890,7 +892,7 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
}
}
- void onTripleTapAndHold(MotionEvent down) {
+ void transitionToViewportDraggingStateAndClear(MotionEvent down) {
if (DEBUG_DETECTING) Slog.i(LOG_TAG, "onTripleTapAndHold()");
clear();
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index d5a722bba723..1ae61af59d84 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -24,7 +24,6 @@ import static com.android.server.autofill.Helper.sDebug;
import static com.android.server.autofill.Helper.sPartitionMaxCount;
import static com.android.server.autofill.Helper.sVerbose;
-import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -56,7 +55,12 @@ import android.os.UserManagerInternal;
import android.provider.Settings;
import android.service.autofill.FillEventHistory;
import android.service.autofill.UserData;
+import android.text.TextUtils;
+import android.text.TextUtils.SimpleStringSplitter;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.LocalLog;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -84,6 +88,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
/**
* Entry point service for autofill management.
@@ -98,6 +103,8 @@ public final class AutofillManagerService extends SystemService {
static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions";
+ private static final char COMPAT_PACKAGE_DELIMITER = ':';
+
private final Context mContext;
private final AutoFillUI mUi;
@@ -123,6 +130,9 @@ public final class AutofillManagerService extends SystemService {
private final LocalLog mUiLatencyHistory = new LocalLog(20);
private final LocalLog mWtfHistory = new LocalLog(50);
+ private final AutofillCompatState mAutofillCompatState = new AutofillCompatState();
+ private final LocalService mLocalService = new LocalService();
+
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -271,7 +281,7 @@ public final class AutofillManagerService extends SystemService {
@Override
public void onStart() {
publishBinderService(AUTOFILL_MANAGER_SERVICE, new AutoFillManagerServiceStub());
- publishLocalService(AutofillManagerInternal.class, new LocalService());
+ publishLocalService(AutofillManagerInternal.class, mLocalService);
}
@Override
@@ -317,6 +327,7 @@ public final class AutofillManagerService extends SystemService {
mUiLatencyHistory, mWtfHistory, resolvedUserId, mUi,
mDisabledUsers.get(resolvedUserId));
mServicesCache.put(userId, service);
+ addCompatibilityModeRequestsLocked(service, userId);
}
return service;
}
@@ -482,6 +493,7 @@ public final class AutofillManagerService extends SystemService {
if (service != null) {
mServicesCache.delete(userId);
service.destroyLocked();
+ mAutofillCompatState.removeCompatibilityModeRequests(userId);
}
}
@@ -504,12 +516,53 @@ public final class AutofillManagerService extends SystemService {
service.updateLocked(disabled);
if (!service.isEnabledLocked()) {
removeCachedServiceLocked(userId);
+ } else {
+ addCompatibilityModeRequestsLocked(service, userId);
}
}
}
- private final class LocalService extends AutofillManagerInternal {
+ private void addCompatibilityModeRequestsLocked(@NonNull AutofillManagerServiceImpl service
+ , int userId) {
+ final ArrayMap<String, Pair<Long, String>> compatPackages =
+ service.getCompatibilityPackagesLocked();
+ if (compatPackages == null || compatPackages.isEmpty()) {
+ return;
+ }
+ final Set<String> whiteListedPackages = getWhitelistedCompatModePackages();
+ final int compatPackageCount = compatPackages.size();
+ for (int i = 0; i < compatPackageCount; i++) {
+ final String packageName = compatPackages.keyAt(i);
+ if (whiteListedPackages == null || !whiteListedPackages.contains(packageName)) {
+ Slog.w(TAG, "Ignoring not whitelisted compat package " + packageName);
+ continue;
+ }
+ final Long maxVersionCode = compatPackages.valueAt(i).first;
+ if (maxVersionCode != null) {
+ mAutofillCompatState.addCompatibilityModeRequest(packageName,
+ maxVersionCode, userId);
+ }
+ }
+ }
+
+ private @Nullable Set<String> getWhitelistedCompatModePackages() {
+ final String compatPackagesSetting = Settings.Global.getString(
+ mContext.getContentResolver(),
+ Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES);
+ if (TextUtils.isEmpty(compatPackagesSetting)) {
+ return null;
+ }
+ final Set<String> compatPackages = new ArraySet<>();
+ final SimpleStringSplitter splitter = new SimpleStringSplitter(
+ COMPAT_PACKAGE_DELIMITER);
+ splitter.setString(compatPackagesSetting);
+ while (splitter.hasNext()) {
+ compatPackages.add(splitter.next());
+ }
+ return compatPackages;
+ }
+ private final class LocalService extends AutofillManagerInternal {
@Override
public void onBackKeyPressed() {
if (sDebug) Slog.d(TAG, "onBackKeyPressed()");
@@ -519,13 +572,59 @@ public final class AutofillManagerService extends SystemService {
@Override
public boolean isCompatibilityModeRequested(@NonNull String packageName,
long versionCode, @UserIdInt int userId) {
+ return mAutofillCompatState.isCompatibilityModeRequested(
+ packageName, versionCode, userId);
+ }
+ }
+
+ private static class AutofillCompatState {
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private SparseArray<ArrayMap<String, Long>> mUserSpecs;
+
+ boolean isCompatibilityModeRequested(@NonNull String packageName,
+ long versionCode, @UserIdInt int userId) {
synchronized (mLock) {
- final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
- if (service != null) {
- return service.isCompatibilityModeRequestedLocked(packageName, versionCode);
+ if (mUserSpecs == null) {
+ return false;
+ }
+ final ArrayMap<String, Long> userSpec = mUserSpecs.get(userId);
+ if (userSpec == null) {
+ return false;
+ }
+ final Long maxVersionCode = userSpec.get(packageName);
+ if (maxVersionCode == null) {
+ return false;
+ }
+ return versionCode <= maxVersionCode;
+ }
+ }
+
+ void addCompatibilityModeRequest(@NonNull String packageName,
+ long versionCode, @UserIdInt int userId) {
+ synchronized (mLock) {
+ if (mUserSpecs == null) {
+ mUserSpecs = new SparseArray<>();
+ }
+ ArrayMap<String, Long> userSpec = mUserSpecs.get(userId);
+ if (userSpec == null) {
+ userSpec = new ArrayMap<>();
+ mUserSpecs.put(userId, userSpec);
+ }
+ userSpec.put(packageName, versionCode);
+ }
+ }
+
+ void removeCompatibilityModeRequests(@UserIdInt int userId) {
+ synchronized (mLock) {
+ if (mUserSpecs != null) {
+ mUserSpecs.remove(userId);
+ if (mUserSpecs.size() <= 0) {
+ mUserSpecs = null;
+ }
}
}
- return false;
}
}
@@ -580,7 +679,7 @@ public final class AutofillManagerService extends SystemService {
@Override
public int startSession(IBinder activityToken, IBinder appCallback, AutofillId autofillId,
Rect bounds, AutofillValue value, int userId, boolean hasCallback, int flags,
- ComponentName componentName) {
+ ComponentName componentName, boolean compatMode) {
activityToken = Preconditions.checkNotNull(activityToken, "activityToken");
appCallback = Preconditions.checkNotNull(appCallback, "appCallback");
@@ -599,7 +698,7 @@ public final class AutofillManagerService extends SystemService {
synchronized (mLock) {
final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
return service.startSessionLocked(activityToken, getCallingUid(), appCallback,
- autofillId, bounds, value, hasCallback, flags, componentName);
+ autofillId, bounds, value, hasCallback, flags, componentName, compatMode);
}
}
@@ -770,7 +869,7 @@ public final class AutofillManagerService extends SystemService {
public int updateOrRestartSession(IBinder activityToken, IBinder appCallback,
AutofillId autoFillId, Rect bounds, AutofillValue value, int userId,
boolean hasCallback, int flags, ComponentName componentName, int sessionId,
- int action) {
+ int action, boolean compatMode) {
boolean restart = false;
synchronized (mLock) {
final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
@@ -783,7 +882,7 @@ public final class AutofillManagerService extends SystemService {
}
if (restart) {
return startSession(activityToken, appCallback, autoFillId, bounds, value, userId,
- hasCallback, flags, componentName);
+ hasCallback, flags, componentName, compatMode);
}
// Nothing changed...
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 2dcc6da0be32..eab4d119e7d2 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -64,6 +64,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.LocalLog;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -220,6 +221,17 @@ final class AutofillManagerServiceImpl {
return mInfo.getServiceInfo().applicationInfo.uid;
}
+
+ @GuardedBy("mLock")
+ @Nullable
+ String getUrlBarResourceIdForCompatModeLocked(@NonNull String packageName) {
+ if (mInfo == null) {
+ Slog.w(TAG, "getUrlBarResourceIdForCompatModeLocked(): no mInfo");
+ return null;
+ }
+ return mInfo.getUrlBarResourceId(packageName);
+ }
+
@Nullable
String getServicePackageName() {
final ComponentName serviceComponent = getServiceComponentName();
@@ -345,7 +357,7 @@ final class AutofillManagerServiceImpl {
int startSessionLocked(@NonNull IBinder activityToken, int uid,
@NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId,
@NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback,
- int flags, @NonNull ComponentName componentName) {
+ int flags, @NonNull ComponentName componentName, boolean compatMode) {
if (!isEnabledLocked()) {
return 0;
}
@@ -375,7 +387,7 @@ final class AutofillManagerServiceImpl {
pruneAbandonedSessionsLocked();
final Session newSession = createSessionByTokenLocked(activityToken, uid, appCallbackToken,
- hasCallback, componentName, flags);
+ hasCallback, componentName, compatMode, flags);
if (newSession == null) {
return NO_SESSION;
}
@@ -481,7 +493,7 @@ final class AutofillManagerServiceImpl {
@GuardedBy("mLock")
private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int uid,
@NonNull IBinder appCallbackToken, boolean hasCallback,
- @NonNull ComponentName componentName, int flags) {
+ @NonNull ComponentName componentName, boolean compatMode, int flags) {
// use random ids so that one app cannot know that another app creates sessions
int sessionId;
int tries = 0;
@@ -499,7 +511,8 @@ final class AutofillManagerServiceImpl {
final Session newSession = new Session(this, mUi, mContext, mHandlerCaller, mUserId, mLock,
sessionId, uid, activityToken, appCallbackToken, hasCallback, mUiLatencyHistory,
- mWtfHistory, mInfo.getServiceInfo().getComponentName(), componentName, flags);
+ mWtfHistory, mInfo.getServiceInfo().getComponentName(), componentName, compatMode,
+ flags);
mSessions.put(newSession.id, newSession);
return newSession;
@@ -857,10 +870,10 @@ final class AutofillManagerServiceImpl {
}
mUserData = userData;
// Log it
- int numberFields = mUserData == null ? 0: mUserData.getRemoteIds().length;
+ int numberFields = mUserData == null ? 0: mUserData.getCategoryIds().length;
mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_USERDATA_UPDATED,
getServicePackageName(), null)
- .setCounterValue(numberFields));
+ .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, numberFields));
}
}
@@ -894,7 +907,10 @@ final class AutofillManagerServiceImpl {
pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled);
pw.print(prefix); pw.print("Field classification enabled: ");
pw.println(isFieldClassificationEnabledLocked());
- pw.print(prefix); pw.print("Compat pkgs: "); pw.println(getWhitelistedCompatModePackages());
+ final ArrayMap<String, Pair<Long, String>> compatPkgs = getCompatibilityPackagesLocked();
+ if (compatPkgs != null) {
+ pw.print(prefix); pw.print("Compat pkgs: "); pw.println(compatPkgs.keySet());
+ }
pw.print(prefix); pw.print("Setup complete: "); pw.println(mSetupComplete);
pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune);
@@ -1018,23 +1034,11 @@ final class AutofillManagerServiceImpl {
}
@GuardedBy("mLock")
- boolean isCompatibilityModeRequestedLocked(@NonNull String packageName,
- long versionCode) {
- if (mInfo == null || !mInfo.isCompatibilityModeRequested(packageName, versionCode)) {
- return false;
+ @Nullable ArrayMap<String, Pair<Long, String>> getCompatibilityPackagesLocked() {
+ if (mInfo != null) {
+ return mInfo.getCompatibilityPackages();
}
- if (!Build.IS_ENG) {
- // TODO: Build a map and watch for settings changes (this is called on app start)
- final String whiteListedPackages = getWhitelistedCompatModePackages();
- return whiteListedPackages != null && whiteListedPackages.contains(packageName);
- }
- return true;
- }
-
- private String getWhitelistedCompatModePackages() {
- return Settings.Global.getString(
- mContext.getContentResolver(),
- Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES);
+ return null;
}
private void sendStateToClients(boolean resetClient) {
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 02a62e10e111..5ef467d44e6a 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -18,11 +18,14 @@ package com.android.server.autofill;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.assist.AssistStructure;
+import android.app.assist.AssistStructure.ViewNode;
import android.metrics.LogMaker;
import android.os.Bundle;
import android.service.autofill.Dataset;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Slog;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
@@ -31,11 +34,14 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.LinkedList;
import java.util.Objects;
import java.util.Set;
public final class Helper {
+ private static final String TAG = "AutofillHelper";
+
/**
* Defines a logging flag that can be dynamically changed at runtime using
* {@code cmd autofill set log_level debug}.
@@ -121,4 +127,61 @@ public final class Helper {
pw.print(text.length()); pw.println("_chars");
}
}
+
+ /**
+ * Finds the {@link ViewNode} that has the requested {@code autofillId}, if any.
+ */
+ @Nullable
+ public static ViewNode findViewNodeByAutofillId(@NonNull AssistStructure structure,
+ @NonNull AutofillId autofillId) {
+ return findViewNode(structure, (node) -> {
+ return autofillId.equals(node.getAutofillId());
+ });
+ }
+
+ private static ViewNode findViewNode(@NonNull AssistStructure structure,
+ @NonNull ViewNodeFilter filter) {
+ final LinkedList<ViewNode> nodesToProcess = new LinkedList<>();
+ final int numWindowNodes = structure.getWindowNodeCount();
+ for (int i = 0; i < numWindowNodes; i++) {
+ nodesToProcess.add(structure.getWindowNodeAt(i).getRootViewNode());
+ }
+ while (!nodesToProcess.isEmpty()) {
+ final ViewNode node = nodesToProcess.removeFirst();
+ if (filter.matches(node)) {
+ return node;
+ }
+ for (int i = 0; i < node.getChildCount(); i++) {
+ nodesToProcess.addLast(node.getChildAt(i));
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Sanitize the {@code webDomain} property of the URL bar node on compat mode.
+ */
+ public static void sanitizeUrlBar(@NonNull AssistStructure structure,
+ @NonNull String urlBarId) {
+ final ViewNode urlBarNode = findViewNode(structure, (node) -> {
+ return urlBarId.equals(node.getIdEntry());
+ });
+ if (urlBarNode != null) {
+ final String domain = urlBarNode.getText().toString();
+ if (domain.isEmpty()) {
+ if (sDebug) Slog.d(TAG, "sanitizeUrlBar(): empty on " + urlBarId);
+ return;
+ }
+ urlBarNode.setWebDomain(domain);
+ if (sDebug) {
+ Slog.d(TAG, "sanitizeUrlBar(): id=" + urlBarId + ", domain="
+ + urlBarNode.getWebDomain());
+ }
+ }
+ }
+
+ private interface ViewNodeFilter {
+ boolean matches(ViewNode node);
+ }
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 4a247049d395..d0475810ee66 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -140,6 +140,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
/** Component that's being auto-filled */
@NonNull private final ComponentName mComponentName;
+ /** Whether the app being autofilled is running in compat mode. */
+ private final boolean mCompatMode;
+
@GuardedBy("mLock")
private final ArrayMap<AutofillId, ViewState> mViewStates = new ArrayMap<>();
@@ -263,6 +266,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
componentNameFromApp == null ? "null"
: componentNameFromApp.flattenToShortString()));
}
+ if (mCompatMode) {
+ // Sanitize URL bar, if needed
+ final String urlBarId = mService.getUrlBarResourceIdForCompatModeLocked(
+ mComponentName.getPackageName());
+ if (sDebug) Slog.d(TAG, "url_bar in compat mode: " + urlBarId);
+ if (urlBarId != null) {
+ Helper.sanitizeUrlBar(structure, urlBarId);
+ }
+ }
structure.sanitizeForParceling(true);
// Flags used to start the session.
@@ -476,7 +488,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
@NonNull IBinder client, boolean hasCallback, @NonNull LocalLog uiLatencyHistory,
@NonNull LocalLog wtfHistory,
@NonNull ComponentName serviceComponentName, @NonNull ComponentName componentName,
- int flags) {
+ boolean compatMode, int flags) {
id = sessionId;
mFlags = flags;
this.uid = uid;
@@ -491,6 +503,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mUiLatencyHistory = uiLatencyHistory;
mWtfHistory = wtfHistory;
mComponentName = componentName;
+ mCompatMode = compatMode;
mClient = IAutoFillManagerClient.Stub.asInterface(client);
mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
@@ -1161,12 +1174,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
@NonNull UserData userData, @NonNull Collection<ViewState> viewStates) {
final String[] userValues = userData.getValues();
- final String[] remoteIds = userData.getRemoteIds();
+ final String[] categoryIds = userData.getCategoryIds();
// Sanity check
- if (userValues == null || remoteIds == null || userValues.length != remoteIds.length) {
+ if (userValues == null || categoryIds == null || userValues.length != categoryIds.length) {
final int valuesLength = userValues == null ? -1 : userValues.length;
- final int idsLength = remoteIds == null ? -1 : remoteIds.length;
+ final int idsLength = categoryIds == null ? -1 : categoryIds.length;
Slog.w(TAG, "setScores(): user data mismatch: values.length = "
+ valuesLength + ", ids.length = " + idsLength);
return;
@@ -1183,12 +1196,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
final int viewsSize = viewStates.size();
// First, we get all scores.
- final AutofillId[] fieldIds = new AutofillId[viewsSize];
+ final AutofillId[] autofillIds = new AutofillId[viewsSize];
final ArrayList<AutofillValue> currentValues = new ArrayList<>(viewsSize);
int k = 0;
for (ViewState viewState : viewStates) {
currentValues.add(viewState.getCurrentValue());
- fieldIds[k++] = viewState.id;
+ autofillIds[k++] = viewState.id;
}
// Then use the results, asynchronously
@@ -1208,32 +1221,53 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
int i = 0, j = 0;
try {
+ // Iteract over all autofill fields first
for (i = 0; i < viewsSize; i++) {
- final AutofillId fieldId = fieldIds[i];
+ final AutofillId autofillId = autofillIds[i];
- ArrayList<Match> matches = null;
+ // Search the best scores for each category (as some categories could have
+ // multiple user values
+ ArrayMap<String, Float> scoresByField = null;
for (j = 0; j < userValues.length; j++) {
- String remoteId = remoteIds[j];
+ final String categoryId = categoryIds[j];
final float score = scores.scores[i][j];
if (score > 0) {
+ if (scoresByField == null) {
+ scoresByField = new ArrayMap<>(userValues.length);
+ }
+ final Float currentScore = scoresByField.get(categoryId);
+ if (currentScore != null && currentScore > score) {
+ if (sVerbose) {
+ Slog.v(TAG, "skipping score " + score
+ + " because it's less than " + currentScore);
+ }
+ continue;
+ }
if (sVerbose) {
Slog.v(TAG, "adding score " + score + " at index " + j + " and id "
- + fieldId);
- }
- if (matches == null) {
- matches = new ArrayList<>(userValues.length);
+ + autofillId);
}
- matches.add(new Match(remoteId, score));
+ scoresByField.put(categoryId, score);
}
else if (sVerbose) {
- Slog.v(TAG, "skipping score 0 at index " + j + " and id " + fieldId);
+ Slog.v(TAG, "skipping score 0 at index " + j + " and id " + autofillId);
}
}
- if (matches != null) {
- detectedFieldIds.add(fieldId);
- detectedFieldClassifications.add(new FieldClassification(matches));
+ if (scoresByField == null) {
+ if (sVerbose) Slog.v(TAG, "no score for autofillId=" + autofillId);
+ continue;
+ }
+
+ // Then create the matches for that autofill id
+ final ArrayList<Match> matches = new ArrayList<>(scoresByField.size());
+ for (j = 0; j < scoresByField.size(); j++) {
+ final String fieldId = scoresByField.keyAt(j);
+ final float score = scoresByField.valueAt(j);
+ matches.add(new Match(fieldId, score));
}
- }
+ detectedFieldIds.add(autofillId);
+ detectedFieldClassifications.add(new FieldClassification(matches));
+ } // for i
} catch (ArrayIndexOutOfBoundsException e) {
wtf(e, "Error accessing FC score at [%d, %d] (%s): %s", i, j, scores, e);
return;
@@ -1537,7 +1571,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
final int numContexts = mContexts.size();
for (int i = numContexts - 1; i >= 0; i--) {
final FillContext context = mContexts.get(i);
- final ViewNode node = context.findViewNodeByAutofillId(id);
+ final ViewNode node = Helper.findViewNodeByAutofillId(context.getStructure(), id);
if (node != null) {
final AutofillValue value = node.getAutofillValue();
if (sDebug) {
@@ -1561,7 +1595,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
for (int i = numContexts - 1; i >= 0; i--) {
final FillContext context = mContexts.get(i);
- final ViewNode node = context.findViewNodeByAutofillId(id);
+ final ViewNode node = Helper.findViewNodeByAutofillId(context.getStructure(), id);
if (node != null && node.getAutofillOptions() != null) {
return node.getAutofillOptions();
}
@@ -2288,6 +2322,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
pw.print(prefix); pw.print("mHasCallback: "); pw.println(mHasCallback);
pw.print(prefix); pw.print("mClientState: "); pw.println(
Helper.bundleToString(mClientState));
+ pw.print(prefix); pw.print("mCompatMode: "); pw.println(mCompatMode);
pw.print(prefix); pw.print("mSelectedDatasetIds: "); pw.println(mSelectedDatasetIds);
mRemoteFillService.dump(prefix, pw);
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 8240e4b758da..c50446514141 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -24,6 +24,7 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.pm.PackageManager;
import android.graphics.Point;
import android.graphics.Rect;
import android.service.autofill.Dataset;
@@ -37,6 +38,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import android.view.autofill.AutofillId;
@@ -98,22 +100,28 @@ final class FillUi {
private @Nullable AnnounceFilterResult mAnnounceFilterResult;
+ private final boolean mFullScreen;
private int mContentWidth;
private int mContentHeight;
private boolean mDestroyed;
+ public static boolean isFullScreen(Context context) {
+ return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ }
+
FillUi(@NonNull Context context, @NonNull FillResponse response,
- @NonNull AutofillId focusedViewId, @NonNull @Nullable String filterText,
- @NonNull OverlayControl overlayControl, @NonNull Callback callback) {
+ @NonNull AutofillId focusedViewId, @NonNull @Nullable String filterText,
+ @NonNull OverlayControl overlayControl, @NonNull Callback callback) {
mContext = context;
mCallback = callback;
+ mFullScreen = isFullScreen(context);
final LayoutInflater inflater = LayoutInflater.from(context);
final ViewGroup decor = (ViewGroup) inflater.inflate(
- R.layout.autofill_dataset_picker, null);
-
+ mFullScreen ? R.layout.autofill_dataset_picker_fullscreen
+ : R.layout.autofill_dataset_picker, null);
final RemoteViews.OnClickHandler interceptionHandler = new RemoteViews.OnClickHandler() {
@Override
@@ -130,31 +138,41 @@ final class FillUi {
mListView = null;
mAdapter = null;
+ // insert authentication item under autofill_dataset_container or decor
+ ViewGroup container = decor.findViewById(R.id.autofill_dataset_container);
+ if (container == null) {
+ container = decor;
+ }
final View content;
try {
content = response.getPresentation().apply(context, decor, interceptionHandler);
- decor.addView(content);
+ container.addView(content);
} catch (RuntimeException e) {
callback.onCanceled();
Slog.e(TAG, "Error inflating remote views", e);
mWindow = null;
return;
}
+ decor.setFocusable(true);
+ decor.setOnClickListener(v -> mCallback.onResponsePicked(response));
Point maxSize = mTempPoint;
resolveMaxWindowSize(context, maxSize);
+ // fullScreen mode occupy the full width defined by autofill_dataset_picker_max_width
+ content.getLayoutParams().width = mFullScreen ? maxSize.x
+ : ViewGroup.LayoutParams.WRAP_CONTENT;
+ content.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(maxSize.x,
MeasureSpec.AT_MOST);
final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxSize.y,
MeasureSpec.AT_MOST);
decor.measure(widthMeasureSpec, heightMeasureSpec);
- decor.setOnClickListener(v -> mCallback.onResponsePicked(response));
mContentWidth = content.getMeasuredWidth();
mContentHeight = content.getMeasuredHeight();
mWindow = new AnchoredWindow(decor, overlayControl);
- mCallback.requestShowFillUi(mContentWidth, mContentHeight, mWindowPresenter);
+ requestShowFillUi();
} else {
final int datasetCount = response.getDatasets().size();
@@ -261,6 +279,15 @@ final class FillUi {
}
}
+ void requestShowFillUi() {
+ if (mFullScreen) {
+ mCallback.requestShowFillUi(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+ mWindowPresenter);
+ } else {
+ mCallback.requestShowFillUi(mContentWidth, mContentHeight, mWindowPresenter);
+ }
+ }
+
/**
* Creates a remoteview interceptor used to block clicks.
*/
@@ -289,7 +316,13 @@ final class FillUi {
mCallback.requestHideFillUi();
} else {
if (updateContentSize()) {
- mCallback.requestShowFillUi(mContentWidth, mContentHeight, mWindowPresenter);
+ if (mFullScreen) {
+ LayoutParams lp = mListView.getLayoutParams();
+ lp.width = mContentWidth;
+ lp.height = mContentHeight;
+ mListView.setLayoutParams(lp);
+ }
+ requestShowFillUi();
}
if (mAdapter.getCount() > VISIBLE_OPTIONS_MAX_COUNT) {
mListView.setVerticalScrollBarEnabled(true);
@@ -310,7 +343,7 @@ final class FillUi {
// ViewState doesn't not support filtering - typically when it's for an authenticated
// FillResponse.
if (TextUtils.isEmpty(filterText)) {
- mCallback.requestShowFillUi(mContentWidth, mContentHeight, mWindowPresenter);
+ requestShowFillUi();
} else {
mCallback.requestHideFillUi();
}
@@ -366,23 +399,39 @@ final class FillUi {
final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxSize.y,
MeasureSpec.AT_MOST);
final int itemCount = mAdapter.getCount();
+ if (mFullScreen) {
+ // fullScreen mode occupy the full width defined by autofill_dataset_picker_max_width
+ changed = true;
+ mContentWidth = maxSize.x;
+ }
for (int i = 0; i < itemCount; i++) {
final View view = mAdapter.getItem(i).view;
view.measure(widthMeasureSpec, heightMeasureSpec);
- final int clampedMeasuredWidth = Math.min(view.getMeasuredWidth(), maxSize.x);
- final int newContentWidth = Math.max(mContentWidth, clampedMeasuredWidth);
- if (newContentWidth != mContentWidth) {
- mContentWidth = newContentWidth;
- changed = true;
- }
- // Update the width to fit only the first items up to max count
- if (i < VISIBLE_OPTIONS_MAX_COUNT) {
- final int clampedMeasuredHeight = Math.min(view.getMeasuredHeight(), maxSize.y);
- final int newContentHeight = mContentHeight + clampedMeasuredHeight;
- if (newContentHeight != mContentHeight) {
- mContentHeight = newContentHeight;
+ if (mFullScreen) {
+ // for fullscreen, add up all children height until hit max height.
+ final int newContentHeight = mContentHeight + view.getMeasuredHeight();
+ final int clampedNewHeight = Math.min(newContentHeight, maxSize.y);
+ if (clampedNewHeight != mContentHeight) {
+ mContentHeight = clampedNewHeight;
+ } else if (view.getMeasuredHeight() > 0) {
+ break;
+ }
+ } else {
+ final int clampedMeasuredWidth = Math.min(view.getMeasuredWidth(), maxSize.x);
+ final int newContentWidth = Math.max(mContentWidth, clampedMeasuredWidth);
+ if (newContentWidth != mContentWidth) {
+ mContentWidth = newContentWidth;
changed = true;
}
+ // Update the width to fit only the first items up to max count
+ if (i < VISIBLE_OPTIONS_MAX_COUNT) {
+ final int clampedMeasuredHeight = Math.min(view.getMeasuredHeight(), maxSize.y);
+ final int newContentHeight = mContentHeight + clampedMeasuredHeight;
+ if (newContentHeight != mContentHeight) {
+ mContentHeight = newContentHeight;
+ changed = true;
+ }
+ }
}
}
return changed;
@@ -575,6 +624,7 @@ final class FillUi {
public void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mCallback: "); pw.println(mCallback != null);
+ pw.print(prefix); pw.print("mFullScreen: "); pw.println(mFullScreen);
pw.print(prefix); pw.print("mListView: "); pw.println(mListView);
pw.print(prefix); pw.print("mAdapter: "); pw.println(mAdapter);
pw.print(prefix); pw.print("mFilterText: ");
diff --git a/services/backup/OWNERS b/services/backup/OWNERS
new file mode 100644
index 000000000000..1c9a43acfa65
--- /dev/null
+++ b/services/backup/OWNERS
@@ -0,0 +1,7 @@
+artikz@google.com
+brufino@google.com
+bryanmawhinney@google.com
+ctate@google.com
+jorlow@google.com
+mkarpinski@google.com
+
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index 7e179e5d24f8..501ff293b535 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -26,6 +26,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArrayMap;
@@ -57,6 +58,8 @@ public class TransportManager {
@VisibleForTesting
public static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
+ private static final String EXTRA_TRANSPORT_REGISTRATION = "transport_registration";
+
private final Intent mTransportServiceIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST);
private final Context mContext;
private final PackageManager mPackageManager;
@@ -582,8 +585,12 @@ public class TransportManager {
String transportString = transportComponent.flattenToShortString();
String callerLogString = "TransportManager.registerTransport()";
- TransportClient transportClient =
- mTransportClientManager.getTransportClient(transportComponent, callerLogString);
+
+ Bundle extras = new Bundle();
+ extras.putBoolean(EXTRA_TRANSPORT_REGISTRATION, true);
+
+ TransportClient transportClient = mTransportClientManager.getTransportClient(
+ transportComponent, extras, callerLogString);
final IBackupTransport transport;
try {
transport = transportClient.connectOrThrow(callerLogString);
diff --git a/services/backup/java/com/android/server/backup/transport/TransportClientManager.java b/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
index 40419323ce0a..96e7d2f53610 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
@@ -22,10 +22,9 @@ import static com.android.server.backup.transport.TransportUtils.formatMessage;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-
+import android.os.Bundle;
import com.android.server.backup.TransportManager;
import com.android.server.backup.transport.TransportUtils.Priority;
-
import java.io.PrintWriter;
import java.util.Map;
import java.util.WeakHashMap;
@@ -59,6 +58,32 @@ public class TransportClientManager {
public TransportClient getTransportClient(ComponentName transportComponent, String caller) {
Intent bindIntent =
new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(transportComponent);
+
+ return getTransportClient(transportComponent, caller, bindIntent);
+ }
+
+ /**
+ * Retrieves a {@link TransportClient} for the transport identified by {@param
+ * transportComponent} whose binding intent will have the {@param extras} extras.
+ *
+ * @param transportComponent The {@link ComponentName} of the transport.
+ * @param extras A {@link Bundle} of extras to pass to the binding intent.
+ * @param caller A {@link String} identifying the caller for logging/debugging purposes. Check
+ * {@link TransportClient#connectAsync(TransportConnectionListener, String)} for more
+ * details.
+ * @return A {@link TransportClient}.
+ */
+ public TransportClient getTransportClient(
+ ComponentName transportComponent, Bundle extras, String caller) {
+ Intent bindIntent =
+ new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(transportComponent);
+ bindIntent.putExtras(extras);
+
+ return getTransportClient(transportComponent, caller, bindIntent);
+ }
+
+ private TransportClient getTransportClient(
+ ComponentName transportComponent, String caller, Intent bindIntent) {
synchronized (mTransportClientsLock) {
TransportClient transportClient =
new TransportClient(
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index a422b7ccd274..9cd3621eb737 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -16,6 +16,13 @@
package com.android.server;
+import static android.app.AlarmManager.ELAPSED_REALTIME;
+import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
+import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE;
+import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
+import static android.app.AlarmManager.RTC;
+import static android.app.AlarmManager.RTC_WAKEUP;
+
import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManager;
@@ -46,6 +53,7 @@ import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
+import android.os.ParcelableException;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
@@ -62,6 +70,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.KeyValueListParser;
import android.util.Log;
+import android.util.NtpTrustedTime;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -70,10 +79,18 @@ import android.util.SparseLongArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.LocalLog;
+import com.android.server.AppStateTracker.Listener;
+
import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
+import java.time.DateTimeException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
@@ -88,21 +105,6 @@ import java.util.TimeZone;
import java.util.TreeSet;
import java.util.function.Predicate;
-import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE;
-import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
-import static android.app.AlarmManager.RTC_WAKEUP;
-import static android.app.AlarmManager.RTC;
-import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
-import static android.app.AlarmManager.ELAPSED_REALTIME;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.DumpUtils;
-import com.android.internal.util.LocalLog;
-import com.android.internal.util.Preconditions;
-import com.android.server.AppStateTracker.Listener;
-
/**
* Alarm manager implementaion.
*
@@ -1794,6 +1796,16 @@ class AlarmManagerService extends SystemService {
}
@Override
+ public long currentNetworkTimeMillis() {
+ final NtpTrustedTime time = NtpTrustedTime.getInstance(getContext());
+ if (time.hasCache()) {
+ return time.currentTimeMillis();
+ } else {
+ throw new ParcelableException(new DateTimeException("Missing NTP fix"));
+ }
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index efad7d5e16a1..f633003e4f07 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -30,6 +30,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
@@ -1290,11 +1291,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
for (Network network : networks) {
nai = getNetworkAgentInfoForNetwork(network);
nc = getNetworkCapabilitiesInternal(nai);
- // nc is a copy of the capabilities in nai, so it's fine to mutate it
- // TODO : don't remove the UIDs when communicating with processes
- // that have the NETWORK_SETTINGS permission.
if (nc != null) {
- nc.setSingleUid(userId);
result.put(network, nc);
}
}
@@ -1362,7 +1359,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (nai != null) {
synchronized (nai) {
if (nai.networkCapabilities != null) {
- return new NetworkCapabilities(nai.networkCapabilities);
+ // TODO : don't remove the UIDs when communicating with processes
+ // that have the NETWORK_SETTINGS permission.
+ return networkCapabilitiesWithoutUids(nai.networkCapabilities);
}
}
}
@@ -1375,6 +1374,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
}
+ private NetworkCapabilities networkCapabilitiesWithoutUids(NetworkCapabilities nc) {
+ return new NetworkCapabilities(nc).setUids(null);
+ }
+
@Override
public NetworkState[] getAllNetworkState() {
// Require internal since we're handing out IMSI details
@@ -1384,6 +1387,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
for (Network network : getAllNetworks()) {
final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
if (nai != null) {
+ // TODO (b/73321673) : NetworkState contains a copy of the
+ // NetworkCapabilities, which may contain UIDs of apps to which the
+ // network applies. Should the UIDs be cleared so as not to leak or
+ // interfere ?
result.add(nai.getNetworkState());
}
}
@@ -4542,10 +4549,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
lp.ensureDirectlyConnectedRoutes();
// TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
// satisfies mDefaultRequest.
+ final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
- new Network(reserveNetId()), new NetworkInfo(networkInfo), lp,
- new NetworkCapabilities(networkCapabilities), currentScore,
+ new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore,
mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest, this);
+ // Make sure the network capabilities reflect what the agent info says.
+ nai.networkCapabilities = mixInCapabilities(nai, nc);
synchronized (this) {
nai.networkMonitor.systemReady = mSystemReady;
}
@@ -4774,6 +4783,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
} else {
newNc.addCapability(NET_CAPABILITY_FOREGROUND);
}
+ if (nai.isSuspended()) {
+ newNc.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ } else {
+ newNc.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ }
return newNc;
}
@@ -4954,7 +4968,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
releasePendingNetworkRequestWithDelay(pendingIntent);
}
- private static void callCallbackForRequest(NetworkRequestInfo nri,
+ private void callCallbackForRequest(NetworkRequestInfo nri,
NetworkAgentInfo networkAgent, int notificationType, int arg1) {
if (nri.messenger == null) {
return; // Default request has no msgr
@@ -4967,16 +4981,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
putParcelable(bundle, networkAgent.network);
}
switch (notificationType) {
+ case ConnectivityManager.CALLBACK_AVAILABLE: {
+ putParcelable(bundle, new NetworkCapabilities(networkAgent.networkCapabilities));
+ putParcelable(bundle, new LinkProperties(networkAgent.linkProperties));
+ break;
+ }
case ConnectivityManager.CALLBACK_LOSING: {
msg.arg1 = arg1;
break;
}
case ConnectivityManager.CALLBACK_CAP_CHANGED: {
+ // networkAgent can't be null as it has been accessed a few lines above.
final NetworkCapabilities nc =
- new NetworkCapabilities(networkAgent.networkCapabilities);
- // TODO : don't remove the UIDs when communicating with processes
- // that have the NETWORK_SETTINGS permission.
- nc.setSingleUid(nri.mUid);
+ networkCapabilitiesWithoutUids(networkAgent.networkCapabilities);
putParcelable(bundle, nc);
break;
}
@@ -5509,6 +5526,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (networkAgent.getCurrentScore() != oldScore) {
rematchAllNetworksAndRequests(networkAgent, oldScore);
}
+ updateCapabilities(networkAgent.getCurrentScore(), networkAgent,
+ networkAgent.networkCapabilities);
+ // TODO (b/73132094) : remove this call once the few users of onSuspended and
+ // onResumed have been removed.
notifyNetworkCallbacks(networkAgent, (state == NetworkInfo.State.SUSPENDED ?
ConnectivityManager.CALLBACK_SUSPENDED :
ConnectivityManager.CALLBACK_RESUMED));
@@ -5545,14 +5566,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, 0);
- // Whether a network is currently suspended is also an important
- // element of state to be transferred (it would not otherwise be
- // delivered by any currently available mechanism).
- if (nai.networkInfo.getState() == NetworkInfo.State.SUSPENDED) {
- callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_SUSPENDED, 0);
- }
- callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_CAP_CHANGED, 0);
- callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_IP_CHANGED, 0);
}
private void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, DetailedState state, int type) {
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index bdeb23163e7e..7cd007bd0b8f 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -120,7 +120,6 @@ import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
import android.text.TextUtils;
import android.text.style.SuggestionSpan;
-import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.EventLog;
@@ -183,7 +182,6 @@ import java.util.concurrent.atomic.AtomicInteger;
public class InputMethodManagerService extends IInputMethodManager.Stub
implements ServiceConnection, Handler.Callback {
static final boolean DEBUG = false;
- static final boolean DEBUG_RESTORE = DEBUG || false;
static final String TAG = "InputMethodManagerService";
@Retention(SOURCE)
@@ -911,15 +909,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|| Intent.ACTION_USER_REMOVED.equals(action)) {
updateCurrentProfileIds();
return;
- } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) {
- final String name = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
- if (Settings.Secure.ENABLED_INPUT_METHODS.equals(name)) {
- final String prevValue = intent.getStringExtra(
- Intent.EXTRA_SETTING_PREVIOUS_VALUE);
- final String newValue = intent.getStringExtra(
- Intent.EXTRA_SETTING_NEW_VALUE);
- restoreEnabledInputMethods(mContext, prevValue, newValue);
- }
} else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
onActionLocaleChanged();
} else if (ACTION_SHOW_INPUT_METHOD_PICKER.equals(action)) {
@@ -984,44 +973,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- // Apply the results of a restore operation to the set of enabled IMEs. Note that this
- // does not attempt to validate on the fly with any installed device policy, so must only
- // be run in the context of initial device setup.
- //
- // TODO: Move this method to InputMethodUtils with adding unit tests.
- static void restoreEnabledInputMethods(Context context, String prevValue, String newValue) {
- if (DEBUG_RESTORE) {
- Slog.i(TAG, "Restoring enabled input methods:");
- Slog.i(TAG, "prev=" + prevValue);
- Slog.i(TAG, " new=" + newValue);
- }
- // 'new' is the just-restored state, 'prev' is what was in settings prior to the restore
- ArrayMap<String, ArraySet<String>> prevMap =
- InputMethodUtils.parseInputMethodsAndSubtypesString(prevValue);
- ArrayMap<String, ArraySet<String>> newMap =
- InputMethodUtils.parseInputMethodsAndSubtypesString(newValue);
-
- // Merge the restored ime+subtype enabled states into the live state
- for (ArrayMap.Entry<String, ArraySet<String>> entry : newMap.entrySet()) {
- final String imeId = entry.getKey();
- ArraySet<String> prevSubtypes = prevMap.get(imeId);
- if (prevSubtypes == null) {
- prevSubtypes = new ArraySet<>(2);
- prevMap.put(imeId, prevSubtypes);
- }
- prevSubtypes.addAll(entry.getValue());
- }
-
- final String mergedImesAndSubtypesString =
- InputMethodUtils.buildInputMethodsAndSubtypesString(prevMap);
- if (DEBUG_RESTORE) {
- Slog.i(TAG, "Merged IME string:");
- Slog.i(TAG, " " + mergedImesAndSubtypesString);
- }
- Settings.Secure.putString(context.getContentResolver(),
- Settings.Secure.ENABLED_INPUT_METHODS, mergedImesAndSubtypesString);
- }
-
final class MyPackageMonitor extends PackageMonitor {
/**
* Package names that are known to contain {@link InputMethodService}.
@@ -1577,7 +1528,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
broadcastFilter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
broadcastFilter.addAction(Intent.ACTION_USER_ADDED);
broadcastFilter.addAction(Intent.ACTION_USER_REMOVED);
- broadcastFilter.addAction(Intent.ACTION_SETTING_RESTORED);
broadcastFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
broadcastFilter.addAction(ACTION_SHOW_INPUT_METHOD_PICKER);
mContext.registerReceiver(new ImmsBroadcastReceiver(), broadcastFilter);
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
index 2c24798204eb..b3a8fb61506b 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java
@@ -23,7 +23,6 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
@@ -33,13 +32,12 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
-import android.os.SystemClock;
import android.os.PowerManager;
+import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;
import android.util.NtpTrustedTime;
import android.util.TimeUtils;
-import android.util.TrustedTime;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.DumpUtils;
@@ -75,19 +73,17 @@ public class NetworkTimeUpdateService extends Binder {
private long mNitzTimeSetTime = NOT_SET;
private Network mDefaultNetwork = null;
- private Context mContext;
- private TrustedTime mTime;
+ private final Context mContext;
+ private final NtpTrustedTime mTime;
+ private final AlarmManager mAlarmManager;
+ private final ConnectivityManager mCM;
+ private final PendingIntent mPendingPollIntent;
+ private final PowerManager.WakeLock mWakeLock;
// NTP lookup is done on this thread and handler
private Handler mHandler;
- private AlarmManager mAlarmManager;
- private PendingIntent mPendingPollIntent;
private SettingsObserver mSettingsObserver;
- private ConnectivityManager mCM;
private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback;
- // The last time that we successfully fetched the NTP time.
- private long mLastNtpFetchTime = NOT_SET;
- private final PowerManager.WakeLock mWakeLock;
// Normal polling frequency
private final long mPollingIntervalMs;
@@ -105,8 +101,9 @@ public class NetworkTimeUpdateService extends Binder {
public NetworkTimeUpdateService(Context context) {
mContext = context;
mTime = NtpTrustedTime.getInstance(context);
- mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ mAlarmManager = mContext.getSystemService(AlarmManager.class);
+ mCM = mContext.getSystemService(ConnectivityManager.class);
+
Intent pollIntent = new Intent(ACTION_POLL, null);
mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
@@ -119,7 +116,7 @@ public class NetworkTimeUpdateService extends Binder {
mTimeErrorThresholdMs = mContext.getResources().getInteger(
com.android.internal.R.integer.config_ntpThreshold);
- mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock(
+ mWakeLock = context.getSystemService(PowerManager.class).newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, TAG);
}
@@ -157,7 +154,7 @@ public class NetworkTimeUpdateService extends Binder {
private void onPollNetworkTime(int event) {
// If Automatic time is not set, don't bother. Similarly, if we don't
// have any default network, don't bother.
- if (!isAutomaticTimeRequested() || mDefaultNetwork == null) return;
+ if (mDefaultNetwork == null) return;
mWakeLock.acquire();
try {
onPollNetworkTimeUnderWakeLock(event);
@@ -167,61 +164,60 @@ public class NetworkTimeUpdateService extends Binder {
}
private void onPollNetworkTimeUnderWakeLock(int event) {
- final long refTime = SystemClock.elapsedRealtime();
- // If NITZ time was received less than mPollingIntervalMs time ago,
- // no need to sync to NTP.
- if (mNitzTimeSetTime != NOT_SET && refTime - mNitzTimeSetTime < mPollingIntervalMs) {
- resetAlarm(mPollingIntervalMs);
- return;
+ // Force an NTP fix when outdated
+ if (mTime.getCacheAge() >= mPollingIntervalMs) {
+ if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh");
+ mTime.forceRefresh();
}
- final long currentTime = System.currentTimeMillis();
- if (DBG) Log.d(TAG, "System time = " + currentTime);
- // Get the NTP time
- if (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + mPollingIntervalMs
- || event == EVENT_AUTO_TIME_CHANGED) {
- if (DBG) Log.d(TAG, "Before Ntp fetch");
-
- // force refresh NTP cache when outdated
- if (mTime.getCacheAge() >= mPollingIntervalMs) {
- mTime.forceRefresh();
+
+ if (mTime.getCacheAge() < mPollingIntervalMs) {
+ // Obtained fresh fix; schedule next normal update
+ resetAlarm(mPollingIntervalMs);
+ if (isAutomaticTimeRequested()) {
+ updateSystemClock(event);
}
- // only update when NTP time is fresh
- if (mTime.getCacheAge() < mPollingIntervalMs) {
- final long ntp = mTime.currentTimeMillis();
- mTryAgainCounter = 0;
- // If the clock is more than N seconds off or this is the first time it's been
- // fetched since boot, set the current time.
- if (Math.abs(ntp - currentTime) > mTimeErrorThresholdMs
- || mLastNtpFetchTime == NOT_SET) {
- // Set the system time
- if (DBG && mLastNtpFetchTime == NOT_SET
- && Math.abs(ntp - currentTime) <= mTimeErrorThresholdMs) {
- Log.d(TAG, "For initial setup, rtc = " + currentTime);
- }
- if (DBG) Log.d(TAG, "Ntp time to be set = " + ntp);
- // Make sure we don't overflow, since it's going to be converted to an int
- if (ntp / 1000 < Integer.MAX_VALUE) {
- SystemClock.setCurrentTimeMillis(ntp);
- }
- } else {
- if (DBG) Log.d(TAG, "Ntp time is close enough = " + ntp);
- }
- mLastNtpFetchTime = SystemClock.elapsedRealtime();
+ } else {
+ // No fresh fix; schedule retry
+ mTryAgainCounter++;
+ if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
+ resetAlarm(mPollingIntervalShorterMs);
} else {
- // Try again shortly
- mTryAgainCounter++;
- if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
- resetAlarm(mPollingIntervalShorterMs);
- } else {
- // Try much later
- mTryAgainCounter = 0;
- resetAlarm(mPollingIntervalMs);
- }
+ // Try much later
+ mTryAgainCounter = 0;
+ resetAlarm(mPollingIntervalMs);
+ }
+ }
+ }
+
+ private long getNitzAge() {
+ if (mNitzTimeSetTime == NOT_SET) {
+ return Long.MAX_VALUE;
+ } else {
+ return SystemClock.elapsedRealtime() - mNitzTimeSetTime;
+ }
+ }
+
+ /**
+ * Consider updating system clock based on current NTP fix, if requested by
+ * user, significant enough delta, and we don't have a recent NITZ.
+ */
+ private void updateSystemClock(int event) {
+ final boolean forceUpdate = (event == EVENT_AUTO_TIME_CHANGED);
+ if (!forceUpdate) {
+ if (getNitzAge() < mPollingIntervalMs) {
+ if (DBG) Log.d(TAG, "Ignoring NTP update due to recent NITZ");
+ return;
+ }
+
+ final long skew = Math.abs(mTime.currentTimeMillis() - System.currentTimeMillis());
+ if (skew < mTimeErrorThresholdMs) {
+ if (DBG) Log.d(TAG, "Ignoring NTP update due to low skew");
return;
}
}
- resetAlarm(mPollingIntervalMs);
+
+ SystemClock.setCurrentTimeMillis(mTime.currentTimeMillis());
}
/**
@@ -326,8 +322,8 @@ public class NetworkTimeUpdateService extends Binder {
pw.print("TimeErrorThresholdMs: ");
TimeUtils.formatDuration(mTimeErrorThresholdMs, pw);
pw.println("\nTryAgainCounter: " + mTryAgainCounter);
- pw.print("LastNtpFetchTime: ");
- TimeUtils.formatDuration(mLastNtpFetchTime, pw);
+ pw.println("NTP cache age: " + mTime.getCacheAge());
+ pw.println("NTP cache certainty: " + mTime.getCacheCertainty());
pw.println();
}
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 1a0068de6852..7c109d5af078 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -16,6 +16,15 @@
package com.android.server;
+import static android.os.storage.OnObbStateChangeListener.ERROR_ALREADY_MOUNTED;
+import static android.os.storage.OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT;
+import static android.os.storage.OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT;
+import static android.os.storage.OnObbStateChangeListener.ERROR_INTERNAL;
+import static android.os.storage.OnObbStateChangeListener.ERROR_NOT_MOUNTED;
+import static android.os.storage.OnObbStateChangeListener.ERROR_PERMISSION_DENIED;
+import static android.os.storage.OnObbStateChangeListener.MOUNTED;
+import static android.os.storage.OnObbStateChangeListener.UNMOUNTED;
+
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
import static com.android.internal.util.XmlUtils.readIntAttribute;
import static com.android.internal.util.XmlUtils.readLongAttribute;
@@ -60,7 +69,6 @@ import android.os.FileUtils;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
-import android.os.IProgressListener;
import android.os.IStoraged;
import android.os.IVold;
import android.os.IVoldListener;
@@ -87,7 +95,6 @@ import android.os.storage.IStorageShutdownObserver;
import android.os.storage.OnObbStateChangeListener;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
-import android.os.storage.StorageResultCode;
import android.os.storage.StorageVolume;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
@@ -137,8 +144,7 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
-import java.security.NoSuchAlgorithmException;
-import java.security.spec.InvalidKeySpecException;
+import java.security.GeneralSecurityException;
import java.security.spec.KeySpec;
import java.util.ArrayList;
import java.util.Arrays;
@@ -3032,8 +3038,8 @@ class StorageManagerService extends IStorageManager.Stub
// If this is the only one pending we might
// have to bind to the service again.
if (!connectToService()) {
- Slog.e(TAG, "Failed to bind to media container service");
- action.handleError();
+ action.notifyObbStateChange(new ObbException(ERROR_INTERNAL,
+ "Failed to bind to media container service"));
return;
}
}
@@ -3049,10 +3055,10 @@ class StorageManagerService extends IStorageManager.Stub
}
if (mContainerService == null) {
// Something seriously wrong. Bail out
- Slog.e(TAG, "Cannot bind to media container service");
for (ObbAction action : mActions) {
// Indicate service bind error
- action.handleError();
+ action.notifyObbStateChange(new ObbException(ERROR_INTERNAL,
+ "Failed to bind to media container service"));
}
mActions.clear();
} else if (mActions.size() > 0) {
@@ -3074,10 +3080,10 @@ class StorageManagerService extends IStorageManager.Stub
disconnectService();
}
if (!connectToService()) {
- Slog.e(TAG, "Failed to bind to media container service");
for (ObbAction action : mActions) {
// Indicate service bind error
- action.handleError();
+ action.notifyObbStateChange(new ObbException(ERROR_INTERNAL,
+ "Failed to bind to media container service"));
}
mActions.clear();
}
@@ -3167,6 +3173,20 @@ class StorageManagerService extends IStorageManager.Stub
}
}
+ private static class ObbException extends Exception {
+ public final int status;
+
+ public ObbException(int status, String message) {
+ super(message);
+ this.status = status;
+ }
+
+ public ObbException(int status, Throwable cause) {
+ super(cause.getMessage(), cause);
+ this.status = status;
+ }
+ }
+
abstract class ObbAction {
private static final int MAX_RETRIES = 3;
private int mRetries;
@@ -3183,46 +3203,44 @@ class StorageManagerService extends IStorageManager.Stub
Slog.i(TAG, "Starting to execute action: " + toString());
mRetries++;
if (mRetries > MAX_RETRIES) {
- Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
- handleError();
+ notifyObbStateChange(new ObbException(ERROR_INTERNAL,
+ "Failed to bind to media container service"));
} else {
handleExecute();
if (DEBUG_OBB)
Slog.i(TAG, "Posting install MCS_UNBIND");
mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
}
- } catch (RemoteException e) {
- if (DEBUG_OBB)
- Slog.i(TAG, "Posting install MCS_RECONNECT");
- mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
- } catch (Exception e) {
- if (DEBUG_OBB)
- Slog.d(TAG, "Error handling OBB action", e);
- handleError();
+ } catch (ObbException e) {
+ notifyObbStateChange(e);
mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
}
}
- abstract void handleExecute() throws RemoteException, IOException;
- abstract void handleError();
+ abstract void handleExecute() throws ObbException;
- protected ObbInfo getObbInfo() throws IOException {
- ObbInfo obbInfo;
+ protected ObbInfo getObbInfo() throws ObbException {
+ final ObbInfo obbInfo;
try {
obbInfo = mContainerService.getObbInfo(mObbState.canonicalPath);
- } catch (RemoteException e) {
- Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
- + mObbState.canonicalPath);
- obbInfo = null;
+ } catch (Exception e) {
+ throw new ObbException(ERROR_PERMISSION_DENIED, e);
}
- if (obbInfo == null) {
- throw new IOException("Couldn't read OBB file: " + mObbState.canonicalPath);
+ if (obbInfo != null) {
+ return obbInfo;
+ } else {
+ throw new ObbException(ERROR_INTERNAL,
+ "Missing OBB info for: " + mObbState.canonicalPath);
}
- return obbInfo;
}
- protected void sendNewStatusOrIgnore(int status) {
+ protected void notifyObbStateChange(ObbException e) {
+ Slog.w(TAG, e);
+ notifyObbStateChange(e.status);
+ }
+
+ protected void notifyObbStateChange(int status) {
if (mObbState == null || mObbState.token == null) {
return;
}
@@ -3246,16 +3264,14 @@ class StorageManagerService extends IStorageManager.Stub
}
@Override
- public void handleExecute() throws IOException, RemoteException {
+ public void handleExecute() throws ObbException {
warnOnNotMounted();
final ObbInfo obbInfo = getObbInfo();
if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) {
- Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
- + " which is owned by " + obbInfo.packageName);
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
- return;
+ throw new ObbException(ERROR_PERMISSION_DENIED, "Denied attempt to mount OBB "
+ + obbInfo.filename + " which is owned by " + obbInfo.packageName);
}
final boolean isMounted;
@@ -3263,9 +3279,8 @@ class StorageManagerService extends IStorageManager.Stub
isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath);
}
if (isMounted) {
- Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
- return;
+ throw new ObbException(ERROR_ALREADY_MOUNTED,
+ "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
}
final String hashedKey;
@@ -3283,28 +3298,16 @@ class StorageManagerService extends IStorageManager.Stub
BigInteger bi = new BigInteger(key.getEncoded());
hashedKey = bi.toString(16);
binderKey = hashedKey;
- } catch (NoSuchAlgorithmException e) {
- Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
- return;
- } catch (InvalidKeySpecException e) {
- Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
- return;
+ } catch (GeneralSecurityException e) {
+ throw new ObbException(ERROR_INTERNAL, e);
}
}
- int rc = StorageResultCode.OperationSucceeded;
try {
mObbState.volId = mVold.createObb(mObbState.canonicalPath, binderKey,
mObbState.ownerGid);
mVold.mount(mObbState.volId, 0, -1);
- } catch (Exception e) {
- Slog.w(TAG, e);
- rc = StorageResultCode.OperationFailedInternalError;
- }
- if (rc == StorageResultCode.OperationSucceeded) {
if (DEBUG_OBB)
Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath);
@@ -3312,20 +3315,13 @@ class StorageManagerService extends IStorageManager.Stub
addObbStateLocked(mObbState);
}
- sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
- } else {
- Slog.e(TAG, "Couldn't mount OBB file: " + rc);
-
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
+ notifyObbStateChange(MOUNTED);
+ } catch (Exception e) {
+ throw new ObbException(ERROR_COULD_NOT_MOUNT, e);
}
}
@Override
- public void handleError() {
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
- }
-
- @Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("MountObbAction{");
@@ -3344,7 +3340,7 @@ class StorageManagerService extends IStorageManager.Stub
}
@Override
- public void handleExecute() throws IOException {
+ public void handleExecute() throws ObbException {
warnOnNotMounted();
final ObbState existingState;
@@ -3353,45 +3349,32 @@ class StorageManagerService extends IStorageManager.Stub
}
if (existingState == null) {
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
- return;
+ throw new ObbException(ERROR_NOT_MOUNTED, "Missing existingState");
}
if (existingState.ownerGid != mObbState.ownerGid) {
- Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath
- + " (owned by GID " + existingState.ownerGid + ")");
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
+ notifyObbStateChange(new ObbException(ERROR_PERMISSION_DENIED,
+ "Permission denied to unmount OBB " + existingState.rawPath
+ + " (owned by GID " + existingState.ownerGid + ")"));
return;
}
- int rc = StorageResultCode.OperationSucceeded;
try {
mVold.unmount(mObbState.volId);
mVold.destroyObb(mObbState.volId);
mObbState.volId = null;
- } catch (Exception e) {
- Slog.w(TAG, e);
- rc = StorageResultCode.OperationFailedInternalError;
- }
- if (rc == StorageResultCode.OperationSucceeded) {
synchronized (mObbMounts) {
removeObbStateLocked(existingState);
}
- sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
- } else {
- Slog.w(TAG, "Could not unmount OBB: " + existingState);
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
+ notifyObbStateChange(UNMOUNTED);
+ } catch (Exception e) {
+ throw new ObbException(ERROR_COULD_NOT_UNMOUNT, e);
}
}
@Override
- public void handleError() {
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
- }
-
- @Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("UnmountObbAction{");
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 6747be340d46..5e5eacb5c767 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -64,6 +64,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.NoSuchElementException;
/**
* Since phone process can be restarted, this class provides a centralized place
@@ -90,6 +91,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
IBinder binder;
+ TelephonyRegistryDeathRecipient deathRecipient;
+
IPhoneStateListener callback;
IOnSubscriptionsChangedListener onSubscriptionsChangedListenerCallback;
@@ -251,6 +254,21 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
};
+ private class TelephonyRegistryDeathRecipient implements IBinder.DeathRecipient {
+
+ private final IBinder binder;
+
+ TelephonyRegistryDeathRecipient(IBinder binder) {
+ this.binder = binder;
+ }
+
+ @Override
+ public void binderDied() {
+ if (DBG) log("binderDied " + binder);
+ remove(binder);
+ }
+ }
+
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -378,23 +396,14 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- Record r;
synchronized (mRecords) {
// register
- find_and_add: {
- IBinder b = callback.asBinder();
- final int N = mRecords.size();
- for (int i = 0; i < N; i++) {
- r = mRecords.get(i);
- if (b == r.binder) {
- break find_and_add;
- }
- }
- r = new Record();
- r.binder = b;
- mRecords.add(r);
- if (DBG) log("listen oscl: add new record");
+ IBinder b = callback.asBinder();
+ Record r = add(b);
+
+ if (r == null) {
+ return;
}
r.onSubscriptionsChangedListenerCallback = callback;
@@ -496,20 +505,11 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
synchronized (mRecords) {
// register
- Record r;
- find_and_add: {
- IBinder b = callback.asBinder();
- final int N = mRecords.size();
- for (int i = 0; i < N; i++) {
- r = mRecords.get(i);
- if (b == r.binder) {
- break find_and_add;
- }
- }
- r = new Record();
- r.binder = b;
- mRecords.add(r);
- if (DBG) log("listen: add new record");
+ IBinder b = callback.asBinder();
+ Record r = add(b);
+
+ if (r == null) {
+ return;
}
r.callback = callback;
@@ -697,16 +697,57 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
return record.canReadPhoneState ? mCallIncomingNumber[phoneId] : "";
}
+ private Record add(IBinder binder) {
+ Record r;
+
+ synchronized (mRecords) {
+ final int N = mRecords.size();
+ for (int i = 0; i < N; i++) {
+ r = mRecords.get(i);
+ if (binder == r.binder) {
+ // Already existed.
+ return r;
+ }
+ }
+ r = new Record();
+ r.binder = binder;
+ r.deathRecipient = new TelephonyRegistryDeathRecipient(binder);
+
+ try {
+ binder.linkToDeath(r.deathRecipient, 0);
+ } catch (RemoteException e) {
+ if (VDBG) log("LinkToDeath remote exception sending to r=" + r + " e=" + e);
+ // Binder already died. Return null.
+ return null;
+ }
+
+ mRecords.add(r);
+ if (DBG) log("add new record");
+ }
+
+ return r;
+ }
+
private void remove(IBinder binder) {
synchronized (mRecords) {
final int recordCount = mRecords.size();
for (int i = 0; i < recordCount; i++) {
- if (mRecords.get(i).binder == binder) {
+ Record r = mRecords.get(i);
+ if (r.binder == binder) {
if (DBG) {
- Record r = mRecords.get(i);
- log("remove: binder=" + binder + "r.callingPackage" + r.callingPackage
- + "r.callback" + r.callback);
+ log("remove: binder=" + binder + " r.callingPackage " + r.callingPackage
+ + " r.callback " + r.callback);
}
+
+ if (r.deathRecipient != null) {
+ try {
+ binder.unlinkToDeath(r.deathRecipient, 0);
+ } catch (NoSuchElementException e) {
+ if (VDBG) log("UnlinkToDeath NoSuchElementException sending to r="
+ + r + " e=" + e);
+ }
+ }
+
mRecords.remove(i);
return;
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 14404f5d4e4f..5fc43732b404 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1095,7 +1095,7 @@ public final class ActiveServices {
active.mNumActive++;
}
r.isForeground = true;
- StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.userId, r.shortName,
+ StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortName,
StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER);
}
r.postNotification();
@@ -1112,7 +1112,7 @@ public final class ActiveServices {
decActiveForegroundAppLocked(smap, r);
}
r.isForeground = false;
- StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.userId, r.shortName,
+ StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortName,
StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT);
if (r.app != null) {
mAm.updateLruProcessLocked(r.app, false, null);
@@ -2538,7 +2538,7 @@ public final class ActiveServices {
cancelForegroundNotificationLocked(r);
if (r.isForeground) {
decActiveForegroundAppLocked(smap, r);
- StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.userId, r.shortName,
+ StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortName,
StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index 87e8121a474d..836791649748 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -81,7 +81,7 @@ class ActivityManagerDebugConfig {
static final boolean DEBUG_FOREGROUND_SERVICE = DEBUG_ALL || false;
static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false;
static final boolean DEBUG_STACK = DEBUG_ALL || false;
- static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || false;
+ static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || true;
static final boolean DEBUG_SWITCH = DEBUG_ALL || false;
static final boolean DEBUG_TASKS = DEBUG_ALL || false;
static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c958b6765358..2af284c12288 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -38,7 +38,6 @@ import static android.app.ActivityManagerInternal.ASSIST_KEY_STRUCTURE;
import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
import static android.app.AppOpsManager.OP_ASSIST_STRUCTURE;
import static android.app.AppOpsManager.OP_NONE;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
@@ -193,6 +192,7 @@ import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS
import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
+import static com.android.server.am.MemoryStatUtil.readMemoryStatFromMemcg;
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
@@ -249,6 +249,7 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.PictureInPictureParams;
+import android.app.ProcessMemoryState;
import android.app.ProfilerInfo;
import android.app.RemoteAction;
import android.app.WaitResult;
@@ -381,6 +382,7 @@ import android.util.proto.ProtoUtils;
import android.view.Gravity;
import android.view.IRecentsAnimationRunner;
import android.view.LayoutInflater;
+import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
import android.view.View;
import android.view.WindowManager;
@@ -436,6 +438,7 @@ import com.android.server.SystemServiceManager;
import com.android.server.ThreadPriorityBooster;
import com.android.server.Watchdog;
import com.android.server.am.ActivityStack.ActivityState;
+import com.android.server.am.MemoryStatUtil.MemoryStat;
import com.android.server.am.proto.ActivityManagerServiceProto;
import com.android.server.am.proto.BroadcastProto;
import com.android.server.am.proto.GrantUriProto;
@@ -454,7 +457,6 @@ import com.android.server.pm.Installer.InstallerException;
import com.android.server.utils.PriorityDump;
import com.android.server.vr.VrManagerInternal;
import com.android.server.wm.PinnedStackWindowController;
-import com.android.server.wm.RecentsAnimationController;
import com.android.server.wm.WindowManagerService;
import dalvik.system.VMRuntime;
@@ -581,6 +583,10 @@ public class ActivityManagerService extends IActivityManager.Stub
// How long we wait until we timeout on key dispatching during instrumentation.
static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
+ // Disable hidden API checks for the newly started instrumentation.
+ // Must be kept in sync with Am.
+ private static final int INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS = 1 << 0;
+
// How long to wait in getAssistContextExtras for the activity and foreground services
// to respond with the result.
static final int PENDING_ASSIST_EXTRAS_TIMEOUT = 500;
@@ -605,6 +611,9 @@ public class ActivityManagerService extends IActivityManager.Stub
// as one line, but close enough for now.
static final int RESERVED_BYTES_PER_LOGCAT_LINE = 100;
+ /** If a UID observer takes more than this long, send a WTF. */
+ private static final int SLOW_UID_OBSERVER_THRESHOLD_MS = 20;
+
// Access modes for handleIncomingUser.
static final int ALLOW_NON_FULL = 0;
static final int ALLOW_NON_FULL_IN_PROFILE = 1;
@@ -777,6 +786,9 @@ public class ActivityManagerService extends IActivityManager.Stub
@VisibleForTesting
long mWaitForNetworkTimeoutMs;
+ /** Total # of UID change events dispatched, shown in dumpsys. */
+ int mUidChangeDispatchCount;
+
/**
* Helper class which strips out priority and proto arguments then calls the dump function with
* the appropriate arguments. If priority arguments are omitted, function calls the legacy
@@ -1699,6 +1711,15 @@ public class ActivityManagerService extends IActivityManager.Stub
final int which;
final int cutpoint;
+ /**
+ * Total # of callback calls that took more than {@link #SLOW_UID_OBSERVER_THRESHOLD_MS}.
+ * We show it in dumpsys.
+ */
+ int mSlowDispatchCount;
+
+ /** Max time it took for each dispatch. */
+ int mMaxDispatchTime;
+
final SparseIntArray lastProcStates;
// Please keep the enum lists in sync
@@ -1908,6 +1929,9 @@ public class ActivityManagerService extends IActivityManager.Stub
final ActivityManagerConstants mConstants;
+ // Encapsulates the global setting "hidden_api_blacklist_exemptions"
+ final HiddenApiBlacklist mHiddenApiBlacklist;
+
PackageManagerInternal mPackageManagerInt;
// VoiceInteraction session ID that changes for each new request except when
@@ -2825,6 +2849,42 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ /**
+ * Encapsulates the globla setting "hidden_api_blacklist_exemptions", including tracking the
+ * latest value via a content observer.
+ */
+ static class HiddenApiBlacklist extends ContentObserver {
+
+ private final Context mContext;
+ private boolean mBlacklistDisabled;
+
+ public HiddenApiBlacklist(Handler handler, Context context) {
+ super(handler);
+ mContext = context;
+ }
+
+ public void registerObserver() {
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS),
+ false,
+ this);
+ update();
+ }
+
+ private void update() {
+ mBlacklistDisabled = "*".equals(Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS));
+ }
+
+ boolean isDisabled() {
+ return mBlacklistDisabled;
+ }
+
+ public void onChange(boolean selfChange) {
+ update();
+ }
+ }
+
@VisibleForTesting
public ActivityManagerService(Injector injector) {
mInjector = injector;
@@ -2859,6 +2919,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mLifecycleManager = null;
mProcStartHandlerThread = null;
mProcStartHandler = null;
+ mHiddenApiBlacklist = null;
}
// Note: This method is invoked on the main thread but may need to attach various
@@ -3002,6 +3063,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
};
+ mHiddenApiBlacklist = new HiddenApiBlacklist(mHandler, mContext);
+
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
@@ -3962,12 +4025,19 @@ public class ActivityManagerService extends IActivityManager.Stub
startProcessLocked(app, hostingType, hostingNameStr, null /* abiOverride */);
}
+ @GuardedBy("this")
+ private final boolean startProcessLocked(ProcessRecord app,
+ String hostingType, String hostingNameStr, String abiOverride) {
+ return startProcessLocked(app, hostingType, hostingNameStr,
+ false /* disableHiddenApiChecks */, abiOverride);
+ }
+
/**
* @return {@code true} if process start is successful, false otherwise.
*/
@GuardedBy("this")
private final boolean startProcessLocked(ProcessRecord app, String hostingType,
- String hostingNameStr, String abiOverride) {
+ String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) {
if (app.pendingStart) {
return true;
}
@@ -4090,10 +4160,12 @@ public class ActivityManagerService extends IActivityManager.Stub
runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
}
- if (app.info.isAllowedToUseHiddenApi()) {
- // This app is allowed to use undocumented and private APIs. Set
- // up its runtime with the appropriate flag.
- runtimeFlags |= Zygote.DISABLE_HIDDEN_API_CHECKS;
+ if (!app.info.isAllowedToUseHiddenApi() &&
+ !disableHiddenApiChecks &&
+ !mHiddenApiBlacklist.isDisabled()) {
+ // This app is not allowed to use undocumented and private APIs, or blacklisting is
+ // enabled. Set up its runtime with the appropriate flag.
+ runtimeFlags |= Zygote.ENABLE_HIDDEN_API_CHECKS;
}
String invokeWith = null;
@@ -4371,7 +4443,7 @@ public class ActivityManagerService extends IActivityManager.Stub
"updateUsageStats: comp=" + component + "res=" + resumed);
final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
StatsLog.write(StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED,
- component.userId, component.realActivity.getPackageName(),
+ component.app.uid, component.realActivity.getPackageName(),
component.realActivity.getShortClassName(), resumed ?
StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__ACTIVITY__MOVE_TO_FOREGROUND :
StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__ACTIVITY__MOVE_TO_BACKGROUND);
@@ -4667,6 +4739,7 @@ public class ActivityManagerService extends IActivityManager.Stub
"*** Delivering " + N + " uid changes");
}
+ mUidChangeDispatchCount += N;
int i = mUidObservers.beginBroadcast();
while (i > 0) {
i--;
@@ -4719,6 +4792,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// interested in all proc state changes.
continue;
}
+ final long start = SystemClock.uptimeMillis();
if ((change & UidRecord.CHANGE_IDLE) != 0) {
if ((reg.which & ActivityManager.UID_OBSERVER_IDLE) != 0) {
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
@@ -4779,6 +4853,13 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
}
+ final int duration = (int) (SystemClock.uptimeMillis() - start);
+ if (reg.mMaxDispatchTime < duration) {
+ reg.mMaxDispatchTime = duration;
+ }
+ if (duration >= SLOW_UID_OBSERVER_THRESHOLD_MS) {
+ reg.mSlowDispatchCount++;
+ }
}
} catch (RemoteException e) {
}
@@ -10059,6 +10140,75 @@ public class ActivityManagerService extends IActivityManager.Stub
}
/**
+ * Updates (grants or revokes) a persitable URI permission.
+ *
+ * @param uri URI to be granted or revoked.
+ * @param prefix if {@code false}, permission apply to this specific URI; if {@code true}, it
+ * applies to all URIs that are prefixed by this URI.
+ * @param packageName target package.
+ * @param grant if {@code true} a new permission will be granted, otherwise an existing
+ * permission will be revoked.
+ * @param userId user handle
+ *
+ * @return whether or not the requested succeeded.
+ *
+ * @deprecated TODO(b/72055774): caller should use takePersistableUriPermission() or
+ * releasePersistableUriPermission() instead, but such change will be made in a separate CL
+ * so it can be easily reverted if it breaks existing functionality.
+ */
+ @Deprecated // STOPSHIP if not removed
+ @Override
+ public boolean updatePersistableUriPermission(Uri uri, boolean prefix, String packageName,
+ boolean grant, int userId) {
+ enforceCallingPermission(android.Manifest.permission.GET_APP_GRANTED_URI_PERMISSIONS,
+ "updatePersistableUriPermission");
+ final int uid = mPackageManagerInt.getPackageUid(packageName, 0, userId);
+
+ final GrantUri grantUri = new GrantUri(userId, uri, prefix);
+
+ boolean persistChanged = false;
+ synchronized (this) {
+ if (grant) { // Grant
+ final String authority = uri.getAuthority();
+ final ProviderInfo pi = getProviderInfoLocked(authority, userId, 0);
+ if (pi == null) {
+ Slog.w(TAG, "No content provider found for authority " + authority);
+ return false;
+ }
+ final UriPermission permission = findOrCreateUriPermissionLocked(pi.packageName,
+ packageName, uid, grantUri);
+ if (permission.isNew()) {
+ final int modeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+ permission.initPersistedModes(modeFlags, System.currentTimeMillis());
+ persistChanged = true;
+ } else {
+ // Caller should not try to grant permission that is already granted.
+ Slog.w(TAG_URI_PERMISSION,
+ "permission already granted for " + grantUri.toSafeString());
+ return false;
+ }
+ persistChanged |= maybePrunePersistedUriGrantsLocked(uid);
+ } else { // Revoke
+ final UriPermission permission = findUriPermissionLocked(uid, grantUri);
+ if (permission == null) {
+ // Caller should not try to revoke permission that is not granted.
+ Slog.v(TAG_URI_PERMISSION, "no permission for " + grantUri.toSafeString());
+ return false;
+ } else {
+ permission.modeFlags = 0;
+ removeUriPermissionIfNeededLocked(permission);
+ persistChanged = true;
+ }
+ }
+ if (persistChanged) {
+ schedulePersistUriGrants();
+ }
+ }
+ return true;
+ }
+
+ /**
* @param uri This uri must NOT contain an embedded userId.
* @param userId The userId in which the uri is to be resolved.
*/
@@ -11322,9 +11472,6 @@ public class ActivityManagerService extends IActivityManager.Stub
throw new IllegalArgumentException("Invalid task, not in foreground");
}
- // When a task is locked, dismiss the pinned stack if it exists
- mStackSupervisor.removeStacksInWindowingModes(WINDOWING_MODE_PINNED);
-
// {@code isSystemCaller} is used to distinguish whether this request is initiated by the
// system or a specific app.
// * System-initiated requests will only start the pinned mode (screen pinning)
@@ -11334,6 +11481,9 @@ public class ActivityManagerService extends IActivityManager.Stub
final int callingUid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
try {
+ // When a task is locked, dismiss the pinned stack if it exists
+ mStackSupervisor.removeStacksInWindowingModes(WINDOWING_MODE_PINNED);
+
mLockTaskController.startLockTaskMode(task, isSystemCaller, callingUid);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -12742,6 +12892,12 @@ public class ActivityManagerService extends IActivityManager.Stub
@GuardedBy("this")
final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
String abiOverride) {
+ return addAppLocked(info, customProcess, isolated, false /* disableHiddenApiChecks */,
+ abiOverride);
+ }
+
+ final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
+ boolean disableHiddenApiChecks, String abiOverride) {
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
@@ -12773,7 +12929,8 @@ public class ActivityManagerService extends IActivityManager.Stub
if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
mPersistentStartingProcesses.add(app);
startProcessLocked(app, "added application",
- customProcess != null ? customProcess : app.processName, abiOverride);
+ customProcess != null ? customProcess : app.processName, disableHiddenApiChecks,
+ abiOverride);
}
return app;
@@ -14578,6 +14735,7 @@ public class ActivityManagerService extends IActivityManager.Stub
NETWORK_ACCESS_TIMEOUT_MS, NETWORK_ACCESS_TIMEOUT_DEFAULT_MS);
final boolean supportsLeanbackOnly =
mContext.getPackageManager().hasSystemFeature(FEATURE_LEANBACK_ONLY);
+ mHiddenApiBlacklist.registerObserver();
// Transfer any global setting for forcing RTL layout, into a System Property
SystemProperties.set(DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
@@ -16662,6 +16820,25 @@ public class ActivityManagerService extends IActivityManager.Stub
pw.print(" mLowRamSinceLastIdle=");
TimeUtils.formatDuration(getLowRamTimeSinceIdle(now), pw);
pw.println();
+ pw.println();
+ pw.print(" mUidChangeDispatchCount=");
+ pw.print(mUidChangeDispatchCount);
+ pw.println();
+
+ pw.println(" Slow UID dispatches:");
+ final int N = mUidObservers.beginBroadcast();
+ for (int i = 0; i < N; i++) {
+ UidObserverRegistration r =
+ (UidObserverRegistration) mUidObservers.getBroadcastCookie(i);
+ pw.print(" ");
+ pw.print(mUidObservers.getBroadcastItem(i).getClass().getTypeName());
+ pw.print(": ");
+ pw.print(r.mSlowDispatchCount);
+ pw.print(" / Max ");
+ pw.print(r.mMaxDispatchTime);
+ pw.println("ms");
+ }
+ mUidObservers.finishBroadcast();
}
}
pw.println(" mForceBackgroundCheck=" + mForceBackgroundCheck);
@@ -18550,6 +18727,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final long myTotalPss = mi.getTotalPss();
final long myTotalSwapPss = mi.getTotalSwappedOutPss();
totalPss += myTotalPss;
+ totalSwapPss += myTotalSwapPss;
nativeProcTotalPss += myTotalPss;
MemItem pssItem = new MemItem(st.name + " (pid " + st.pid + ")",
@@ -21582,7 +21760,10 @@ public class ActivityManagerService extends IActivityManager.Stub
mUsageStatsService.reportEvent(ii.targetPackage, userId,
UsageEvents.Event.SYSTEM_INTERACTION);
}
- ProcessRecord app = addAppLocked(ai, defProcess, false, abiOverride);
+ boolean disableHiddenApiChecks =
+ (flags & INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0;
+ ProcessRecord app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks,
+ abiOverride);
app.instr = activeInstr;
activeInstr.mFinished = false;
activeInstr.mRunningProcesses.add(app);
@@ -25962,6 +26143,33 @@ public class ActivityManagerService extends IActivityManager.Stub
return (uidRec != null) && !uidRec.idle;
}
}
+
+ @Override
+ public List<ProcessMemoryState> getMemoryStateForProcesses() {
+ List<ProcessMemoryState> processMemoryStates = new ArrayList<>();
+ synchronized (mPidsSelfLocked) {
+ for (int i = 0, size = mPidsSelfLocked.size(); i < size; i++) {
+ final ProcessRecord r = mPidsSelfLocked.valueAt(i);
+ final int pid = r.pid;
+ final int uid = r.uid;
+ final MemoryStat memoryStat = readMemoryStatFromMemcg(uid, pid);
+ if (memoryStat == null) {
+ continue;
+ }
+ ProcessMemoryState processMemoryState =
+ new ProcessMemoryState(uid,
+ r.processName,
+ r.maxAdj,
+ memoryStat.pgfault,
+ memoryStat.pgmajfault,
+ memoryStat.rssInBytes,
+ memoryStat.cacheInBytes,
+ memoryStat.swapInBytes);
+ processMemoryStates.add(processMemoryState);
+ }
+ }
+ return processMemoryStates;
+ }
}
/**
@@ -26294,4 +26502,20 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
}
+
+ @Override
+ public void registerRemoteAnimationForNextActivityStart(String packageName,
+ RemoteAnimationAdapter adapter) throws RemoteException {
+ enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
+ "registerRemoteAnimationForNextActivityStart");
+ synchronized (this) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ mActivityStartController.registerRemoteAnimationForNextActivityStart(packageName,
+ adapter);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 24a77c7693d0..fa0df562b6c6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2608,7 +2608,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" specified then send to all users.");
pw.println(" --receiver-permission <PERMISSION>: Require receiver to hold permission.");
pw.println(" instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]");
- pw.println(" [--user <USER_ID> | current]");
+ pw.println(" [--user <USER_ID> | current] [--no-hidden-api-checks]");
pw.println(" [--no-window-animation] [--abi <ABI>] <COMPONENT>");
pw.println(" Start an Instrumentation. Typically this target <COMPONENT> is in the");
pw.println(" form <TEST_PACKAGE>/<RUNNER_CLASS> or only <TEST_PACKAGE> if there");
@@ -2626,6 +2626,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" test runners.");
pw.println(" --user <USER_ID> | current: Specify user instrumentation runs in;");
pw.println(" current user if not specified.");
+ pw.println(" --no-hidden-api-checks: disable restrictions on use of hidden API.");
pw.println(" --no-window-animation: turn off window animations while running.");
pw.println(" --abi <ABI>: Launch the instrumented process with the selected ABI.");
pw.println(" This assumes that the process supports the selected ABI.");
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 9838851a56cf..ddba349dbe86 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -380,8 +380,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
String getLifecycleDescription(String reason) {
- return "component:" + intent.getComponent().flattenToShortString() + ", state=" + state
- + ", reason=" + reason + ", time=" + System.currentTimeMillis();
+ return "name= " + this + ", component=" + intent.getComponent().flattenToShortString()
+ + ", package=" + packageName + ", state=" + state + ", reason=" + reason + ", time="
+ + System.currentTimeMillis();
}
void dump(PrintWriter pw, String prefix) {
@@ -2583,7 +2584,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(service.isNextTransitionForward());
} else {
- lifecycleItem = PauseActivityItem.obtain();
+ lifecycleItem = PauseActivityItem.obtain()
+ .setDescription(getLifecycleDescription("relaunchActivityLocked"));
}
final ClientTransaction transaction = ClientTransaction.obtain(app.thread, appToken);
transaction.addCallback(callbackItem);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 055a1aa4bbca..812de88729de 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1444,7 +1444,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
mService.mLifecycleManager.scheduleTransaction(prev.app.thread, prev.appToken,
PauseActivityItem.obtain(prev.finishing, userLeaving,
- prev.configChangeFlags, pauseImmediately));
+ prev.configChangeFlags, pauseImmediately).setDescription(
+ prev.getLifecycleDescription("startPausingLocked")));
} catch (Exception e) {
// Ignore exception, if process died other code will cleanup.
Slog.w(TAG, "Exception thrown during pause", e);
@@ -1524,7 +1525,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (r.finishing) {
if (DEBUG_PAUSE) Slog.v(TAG,
"Executing finish of failed to pause activity: " + r);
- finishCurrentActivityLocked(r, FINISH_AFTER_VISIBLE, false);
+ finishCurrentActivityLocked(r, FINISH_AFTER_VISIBLE, false,
+ "activityPausedLocked");
}
}
}
@@ -1541,7 +1543,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
prev.state = ActivityState.PAUSED;
if (prev.finishing) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
- prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false);
+ prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false,
+ "completedPausedLocked");
} else if (prev.app != null) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
+ " wasStopping=" + wasStopping + " visible=" + prev.visible);
@@ -3673,8 +3676,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
final int finishMode = (r.visible || r.nowVisible) ? FINISH_AFTER_VISIBLE
: FINISH_AFTER_PAUSE;
- final boolean removedActivity = finishCurrentActivityLocked(r, finishMode, oomAdj)
- == null;
+ final boolean removedActivity = finishCurrentActivityLocked(r, finishMode, oomAdj,
+ "finishActivityLocked") == null;
// The following code is an optimization. When the last non-task overlay activity
// is removed from the task, we remove the entire task from the stack. However,
@@ -3715,7 +3718,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
static final int FINISH_AFTER_PAUSE = 1;
static final int FINISH_AFTER_VISIBLE = 2;
- final ActivityRecord finishCurrentActivityLocked(ActivityRecord r, int mode, boolean oomAdj) {
+ final ActivityRecord finishCurrentActivityLocked(ActivityRecord r, int mode, boolean oomAdj,
+ String reason) {
// First things first: if this activity is currently visible,
// and the resumed activity is not yet visible, then hold off on
// finishing until the resumed one becomes visible.
@@ -3758,7 +3762,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
|| prevState == STOPPED
|| prevState == ActivityState.INITIALIZING) {
r.makeFinishingLocked();
- boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm");
+ boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm:" + reason);
if (finishingActivityInNonFocusedStack) {
// Finishing activity that was in paused state and it was in not currently focused
@@ -3794,7 +3798,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
continue;
}
Slog.d(TAG, "finishAllActivitiesLocked: finishing " + r + " immediately");
- finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false);
+ finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false,
+ "finishAllActivitiesLocked");
}
}
if (noActivitiesInStack) {
@@ -4882,7 +4887,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
+ r.intent.getComponent().flattenToShortString());
// Force the destroy to skip right to removal.
r.app = null;
- finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false);
+ finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false,
+ "handleAppCrashedLocked");
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 4928e908ce44..f4f60c2c43a9 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1453,7 +1453,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward())
.setDescription(r.getLifecycleDescription("realStartActivityLocked"));
} else {
- lifecycleItem = PauseActivityItem.obtain();
+ lifecycleItem = PauseActivityItem.obtain()
+ .setDescription(r.getLifecycleDescription("realStartActivityLocked"));
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);
@@ -1955,7 +1956,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
final ActivityStack stack = r.getStack();
if (stack != null) {
if (r.finishing) {
- stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false);
+ stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false,
+ "activityIdleInternalLocked");
} else {
stack.stopActivityLocked(r);
}
@@ -4514,7 +4516,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
int startActivityFromRecents(int callingPid, int callingUid, int taskId,
SafeActivityOptions options) {
- final TaskRecord task;
+ TaskRecord task = null;
final String callingPackage;
final Intent intent;
final int userId;
@@ -4577,13 +4579,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
targetActivity);
}
- // If we are launching the task in the docked stack, put it into resizing mode so
- // the window renders full-screen with the background filling the void. Also only
- // call this at the end to make sure that tasks exists on the window manager side.
- if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- setResizingDuringAnimation(task);
- }
-
mService.getActivityStartController().postStartActivityProcessingForLastStarter(
task.getTopActivity(), ActivityManager.START_TASK_TO_FRONT,
task.getStack());
@@ -4593,15 +4588,28 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
intent = task.intent;
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
userId = task.userId;
- int result = mService.getActivityStartController().startActivityInPackage(
+ return mService.getActivityStartController().startActivityInPackage(
task.mCallingUid, callingPid, callingUid, callingPackage, intent, null, null,
- null, 0, 0, options, userId, task,
- "startActivityFromRecents");
- if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+ null, 0, 0, options, userId, task, "startActivityFromRecents");
+ } finally {
+ if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && task != null) {
+ // If we are launching the task in the docked stack, put it into resizing mode so
+ // the window renders full-screen with the background filling the void. Also only
+ // call this at the end to make sure that tasks exists on the window manager side.
setResizingDuringAnimation(task);
+
+ final ActivityDisplay display = task.getStack().getDisplay();
+ final ActivityStack topSecondaryStack =
+ display.getTopStackInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ if (topSecondaryStack.isActivityTypeHome()) {
+ // If the home activity if the top split-screen secondary stack, then the
+ // primary split-screen stack is in the minimized mode which means it can't
+ // receive input keys, so we should move the focused app to the home app so that
+ // window manager can correctly calculate the focus window that can receive
+ // input keys.
+ moveHomeStackToFront("startActivityFromRecents: homeVisibleInSplitScreen");
+ }
}
- return result;
- } finally {
mWindowManager.continueSurfaceLayout();
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java
index f24809a097e1..868f90df5c1b 100644
--- a/services/core/java/com/android/server/am/ActivityStartController.java
+++ b/services/core/java/com/android/server/am/ActivityStartController.java
@@ -41,6 +41,7 @@ import android.os.Looper;
import android.os.Message;
import android.provider.Settings;
import android.util.Slog;
+import android.view.RemoteAnimationAdapter;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
@@ -85,6 +86,8 @@ public class ActivityStartController {
private final Handler mHandler;
+ private final PendingRemoteAnimationRegistry mPendingRemoteAnimationRegistry;
+
private final class StartHandler extends Handler {
public StartHandler(Looper looper) {
super(looper, null, true);
@@ -123,6 +126,8 @@ public class ActivityStartController {
mHandler = new StartHandler(mService.mHandlerThread.getLooper());
mFactory = factory;
mFactory.setController(this);
+ mPendingRemoteAnimationRegistry = new PendingRemoteAnimationRegistry(service,
+ service.mHandler);
}
/**
@@ -248,11 +253,11 @@ public class ActivityStartController {
/**
* Start intents as a package.
*
- * @param uid make a call as if this UID did.
- * @param callingPackage make a call as if this package did.
- * @param intents intents to start.
- * @param userId start the intents on this user.
- * @param validateIncomingUser set true to skip checking {@code userId} with the calling UID.
+ * @param uid Make a call as if this UID did.
+ * @param callingPackage Make a call as if this package did.
+ * @param intents Intents to start.
+ * @param userId Start the intents on this user.
+ * @param validateIncomingUser Set true to skip checking {@code userId} with the calling UID.
*/
final int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents,
String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
@@ -399,6 +404,15 @@ public class ActivityStartController {
return mPendingActivityLaunches.size() < pendingLaunches;
}
+ void registerRemoteAnimationForNextActivityStart(String packageName,
+ RemoteAnimationAdapter adapter) {
+ mPendingRemoteAnimationRegistry.addPendingAnimation(packageName, adapter);
+ }
+
+ PendingRemoteAnimationRegistry getPendingRemoteAnimationRegistry() {
+ return mPendingRemoteAnimationRegistry;
+ }
+
void dump(PrintWriter pw, String prefix, String dumpPackage) {
pw.print(prefix);
pw.print("mLastHomeActivityStartResult=");
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 055b89b6a6f0..8205265ba047 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -708,6 +708,8 @@ class ActivityStarter {
ActivityOptions checkedOptions = options != null
? options.getOptions(intent, aInfo, callerApp, mSupervisor)
: null;
+ checkedOptions = mService.getActivityStartController().getPendingRemoteAnimationRegistry()
+ .overrideOptionsIfNeeded(callingPackage, checkedOptions);
if (mService.mController != null) {
try {
// The Intent we give to the watcher has the extra data
@@ -930,6 +932,7 @@ class ActivityStarter {
// Don't modify the client's object!
intent = new Intent(intent);
if (componentSpecified
+ && !(Intent.ACTION_VIEW.equals(intent.getAction()) && intent.getData() == null)
&& !Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE.equals(intent.getAction())
&& !Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE.equals(intent.getAction())
&& mService.getPackageManagerInternalLocked()
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index ef82f36fa79f..1f101814d294 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -43,7 +43,10 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
@@ -65,12 +68,13 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
// There is some accuracy error in wifi reports so allow some slop in the results.
private static final long MAX_WIFI_STATS_SAMPLE_ERROR_MILLIS = 750;
- private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor(
- (ThreadFactory) r -> {
- Thread t = new Thread(r, "batterystats-worker");
- t.setPriority(Thread.NORM_PRIORITY);
- return t;
- });
+ private final ScheduledExecutorService mExecutorService =
+ Executors.newSingleThreadScheduledExecutor(
+ (ThreadFactory) r -> {
+ Thread t = new Thread(r, "batterystats-worker");
+ t.setPriority(Thread.NORM_PRIORITY);
+ return t;
+ });
private final Context mContext;
private final BatteryStatsImpl mStats;
@@ -85,8 +89,20 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
private String mCurrentReason = null;
@GuardedBy("this")
+ private boolean mOnBattery;
+
+ @GuardedBy("this")
+ private boolean mOnBatteryScreenOff;
+
+ @GuardedBy("this")
+ private boolean mUseLatestStates = true;
+
+ @GuardedBy("this")
private final IntArray mUidsToRemove = new IntArray();
+ @GuardedBy("this")
+ private Future<?> mWakelockChangesUpdate;
+
private final Object mWorkerLock = new Object();
@GuardedBy("mWorkerLock")
@@ -123,7 +139,8 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
}
@Override
- public Future<?> scheduleReadProcStateCpuTimes(boolean onBattery, boolean onBatteryScreenOff) {
+ public Future<?> scheduleReadProcStateCpuTimes(
+ boolean onBattery, boolean onBatteryScreenOff, long delayMillis) {
synchronized (mStats) {
if (!mStats.trackPerProcStateCpuTimes()) {
return null;
@@ -131,9 +148,10 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
}
synchronized (BatteryExternalStatsWorker.this) {
if (!mExecutorService.isShutdown()) {
- return mExecutorService.submit(PooledLambda.obtainRunnable(
+ return mExecutorService.schedule(PooledLambda.obtainRunnable(
BatteryStatsImpl::updateProcStateCpuTimes,
- mStats, onBattery, onBatteryScreenOff).recycleOnUse());
+ mStats, onBattery, onBatteryScreenOff).recycleOnUse(),
+ delayMillis, TimeUnit.MILLISECONDS);
}
}
return null;
@@ -157,6 +175,50 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
return null;
}
+ @Override
+ public Future<?> scheduleCpuSyncDueToScreenStateChange(
+ boolean onBattery, boolean onBatteryScreenOff) {
+ synchronized (BatteryExternalStatsWorker.this) {
+ if (mCurrentFuture == null || (mUpdateFlags & UPDATE_CPU) == 0) {
+ mOnBattery = onBattery;
+ mOnBatteryScreenOff = onBatteryScreenOff;
+ mUseLatestStates = false;
+ }
+ return scheduleSyncLocked("screen-state", UPDATE_CPU);
+ }
+ }
+
+ @Override
+ public Future<?> scheduleCpuSyncDueToWakelockChange(long delayMillis) {
+ if (mExecutorService.isShutdown()) {
+ return CompletableFuture.failedFuture(new IllegalStateException("worker shutdown"));
+ }
+
+ if (mWakelockChangesUpdate != null) {
+ // If there's already a scheduled task, leave it as is if we're trying to re-schedule
+ // it again with a delay, otherwise cancel and re-schedule it.
+ if (delayMillis == 0) {
+ mWakelockChangesUpdate.cancel(false);
+ } else {
+ return mWakelockChangesUpdate;
+ }
+ }
+
+ mWakelockChangesUpdate = mExecutorService.schedule(() -> {
+ scheduleSync("wakelock-change", UPDATE_CPU);
+ scheduleRunnable(() -> mStats.postBatteryNeedsCpuUpdateMsg());
+ mWakelockChangesUpdate = null;
+ }, delayMillis, TimeUnit.MILLISECONDS);
+ return mWakelockChangesUpdate;
+ }
+
+ @Override
+ public void cancelCpuSyncDueToWakelockChange() {
+ if (mWakelockChangesUpdate != null) {
+ mWakelockChangesUpdate.cancel(false);
+ }
+ }
+
public synchronized Future<?> scheduleWrite() {
if (mExecutorService.isShutdown()) {
return CompletableFuture.failedFuture(new IllegalStateException("worker shutdown"));
@@ -204,14 +266,21 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
final int updateFlags;
final String reason;
final int[] uidsToRemove;
+ final boolean onBattery;
+ final boolean onBatteryScreenOff;
+ final boolean useLatestStates;
synchronized (BatteryExternalStatsWorker.this) {
updateFlags = mUpdateFlags;
reason = mCurrentReason;
uidsToRemove = mUidsToRemove.size() > 0 ? mUidsToRemove.toArray() : EmptyArray.INT;
+ onBattery = mOnBattery;
+ onBatteryScreenOff = mOnBatteryScreenOff;
+ useLatestStates = mUseLatestStates;
mUpdateFlags = 0;
mCurrentReason = null;
mUidsToRemove.clear();
mCurrentFuture = null;
+ mUseLatestStates = true;
}
synchronized (mWorkerLock) {
@@ -219,7 +288,8 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
Slog.d(TAG, "begin updateExternalStatsSync reason=" + reason);
}
try {
- updateExternalStatsLocked(reason, updateFlags);
+ updateExternalStatsLocked(reason, updateFlags, onBattery,
+ onBatteryScreenOff, useLatestStates);
} finally {
if (DEBUG) {
Slog.d(TAG, "end updateExternalStatsSync");
@@ -250,7 +320,8 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
};
@GuardedBy("mWorkerLock")
- private void updateExternalStatsLocked(final String reason, int updateFlags) {
+ private void updateExternalStatsLocked(final String reason, int updateFlags,
+ boolean onBattery, boolean onBatteryScreenOff, boolean useLatestStates) {
// We will request data from external processes asynchronously, and wait on a timeout.
SynchronousResultReceiver wifiReceiver = null;
SynchronousResultReceiver bluetoothReceiver = null;
@@ -306,7 +377,14 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
reason, 0);
if ((updateFlags & UPDATE_CPU) != 0) {
- mStats.updateCpuTimeLocked();
+ if (useLatestStates) {
+ onBattery = mStats.isOnBatteryLocked();
+ onBatteryScreenOff = mStats.isOnBatteryScreenOffLocked();
+ }
+ mStats.updateCpuTimeLocked(onBattery, onBatteryScreenOff);
+ }
+
+ if ((updateFlags & UPDATE_ALL) != 0) {
mStats.updateKernelWakelocksLocked();
mStats.updateKernelMemoryBandwidthLocked();
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index ea52782027ba..9d1adb23957b 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1057,7 +1057,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
// to block such a low level service like BatteryService on external stats like WiFi.
mWorker.scheduleRunnable(() -> {
synchronized (mStats) {
- final boolean onBattery = plugType == BatteryStatsImpl.BATTERY_PLUGGED_NONE;
+ final boolean onBattery = BatteryStatsImpl.isOnBattery(plugType, status);
if (mStats.isOnBattery() == onBattery) {
// The battery state has not changed, so we don't need to sync external
// stats immediately.
diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java
index d97c2a24ef1e..a2a84ec43ed2 100644
--- a/services/core/java/com/android/server/am/MemoryStatUtil.java
+++ b/services/core/java/com/android/server/am/MemoryStatUtil.java
@@ -28,7 +28,7 @@ import com.android.internal.annotations.VisibleForTesting;
import java.io.File;
import java.io.IOException;
-import java.util.ArrayList;
+import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -52,8 +52,9 @@ final class MemoryStatUtil {
/**
* Reads memory.stat of a process from memcg.
*/
- static @Nullable MemoryStat readMemoryStatFromMemcg(int uid, int pid) {
- final String memoryStatPath = String.format(MEMORY_STAT_FILE_FMT, uid, pid);
+ @Nullable
+ static MemoryStat readMemoryStatFromMemcg(int uid, int pid) {
+ final String memoryStatPath = String.format(Locale.US, MEMORY_STAT_FILE_FMT, uid, pid);
final File memoryStatFile = new File(memoryStatPath);
if (!memoryStatFile.exists()) {
if (DEBUG_METRICS) Slog.i(TAG, memoryStatPath + " not found");
@@ -74,7 +75,8 @@ final class MemoryStatUtil {
* Parses relevant statistics out from the contents of a memory.stat file in memcg.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- static @Nullable MemoryStat parseMemoryStat(String memoryStatContents) {
+ @Nullable
+ static MemoryStat parseMemoryStat(String memoryStatContents) {
MemoryStat memoryStat = new MemoryStat();
if (memoryStatContents == null) {
return memoryStat;
diff --git a/services/core/java/com/android/server/am/PendingRemoteAnimationRegistry.java b/services/core/java/com/android/server/am/PendingRemoteAnimationRegistry.java
new file mode 100644
index 000000000000..77713f57d017
--- /dev/null
+++ b/services/core/java/com/android/server/am/PendingRemoteAnimationRegistry.java
@@ -0,0 +1,86 @@
+/*
+ * 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
+ */
+
+package com.android.server.am;
+
+import android.annotation.Nullable;
+import android.app.ActivityOptions;
+import android.os.Handler;
+import android.util.ArrayMap;
+import android.view.RemoteAnimationAdapter;
+
+/**
+ * Registry to keep track of remote animations to be run for activity starts from a certain package.
+ *
+ * @see ActivityManagerService#registerRemoteAnimationForNextActivityStart
+ */
+class PendingRemoteAnimationRegistry {
+
+ private static final long TIMEOUT_MS = 3000;
+
+ private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
+ private final Handler mHandler;
+ private final ActivityManagerService mService;
+
+ PendingRemoteAnimationRegistry(ActivityManagerService service, Handler handler) {
+ mService = service;
+ mHandler = handler;
+ }
+
+ /**
+ * Adds a remote animation to be run for all activity starts originating from a certain package.
+ */
+ void addPendingAnimation(String packageName, RemoteAnimationAdapter adapter) {
+ mEntries.put(packageName, new Entry(packageName, adapter));
+ }
+
+ /**
+ * Overrides the activity options with a registered remote animation for a certain calling
+ * package if such a remote animation is registered.
+ */
+ ActivityOptions overrideOptionsIfNeeded(String callingPackage,
+ @Nullable ActivityOptions options) {
+ final Entry entry = mEntries.get(callingPackage);
+ if (entry == null) {
+ return options;
+ }
+ if (options == null) {
+ options = ActivityOptions.makeRemoteAnimation(entry.adapter);
+ } else {
+ options.setRemoteAnimationAdapter(entry.adapter);
+ }
+ mEntries.remove(callingPackage);
+ return options;
+ }
+
+ private class Entry {
+ final String packageName;
+ final RemoteAnimationAdapter adapter;
+
+ Entry(String packageName, RemoteAnimationAdapter adapter) {
+ this.packageName = packageName;
+ this.adapter = adapter;
+ mHandler.postDelayed(() -> {
+ synchronized (mService) {
+ final Entry entry = mEntries.get(packageName);
+ if (entry == this) {
+ mEntries.remove(packageName);
+ }
+ }
+ }, TIMEOUT_MS);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java
index db4e09fb79b8..6dcf04193c8e 100644
--- a/services/core/java/com/android/server/am/RecentsAnimation.java
+++ b/services/core/java/com/android/server/am/RecentsAnimation.java
@@ -28,7 +28,9 @@ import android.app.ActivityOptions;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Handler;
+import android.os.RemoteException;
import android.os.Trace;
+import android.util.Slog;
import android.view.IRecentsAnimationRunner;
import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks;
import com.android.server.wm.WindowManagerService;
@@ -63,6 +65,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks {
mHandler = new Handler(mStackSupervisor.mLooper);
mWindowManager = wm;
mUserController = userController;
+
mCancelAnimationRunnable = () -> {
// The caller has not finished the animation in a predefined amount of time, so
// force-cancel the animation
@@ -73,13 +76,33 @@ class RecentsAnimation implements RecentsAnimationCallbacks {
void startRecentsActivity(Intent intent, IRecentsAnimationRunner recentsAnimationRunner,
ComponentName recentsComponent, int recentsUid) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "RecentsAnimation#startRecentsActivity");
+
+ if (!mWindowManager.canStartRecentsAnimation()) {
+ notifyAnimationCancelBeforeStart(recentsAnimationRunner);
+ return;
+ }
+
+ // If the existing home activity is already on top, then cancel
+ ActivityRecord homeActivity = mStackSupervisor.getHomeActivity();
+ final boolean hasExistingHomeActivity = homeActivity != null;
+ if (hasExistingHomeActivity) {
+ final ActivityDisplay display = homeActivity.getDisplay();
+ mRestoreHomeBehindStack = display.getStackAboveHome();
+ if (mRestoreHomeBehindStack == null) {
+ notifyAnimationCancelBeforeStart(recentsAnimationRunner);
+ return;
+ }
+ }
+
mWindowManager.deferSurfaceLayout();
try {
- // Cancel the previous recents animation if necessary
- mWindowManager.cancelRecentsAnimation();
- final boolean hasExistingHomeActivity = mStackSupervisor.getHomeActivity() != null;
- if (!hasExistingHomeActivity) {
+ final ActivityDisplay display;
+ if (hasExistingHomeActivity) {
+ // Move the home activity into place for the animation if it is not already top most
+ display = homeActivity.getDisplay();
+ display.moveHomeStackBehindBottomMostVisibleStack();
+ } else {
// No home activity
final ActivityOptions opts = ActivityOptions.makeBasic();
opts.setLaunchActivityType(ACTIVITY_TYPE_HOME);
@@ -95,25 +118,20 @@ class RecentsAnimation implements RecentsAnimationCallbacks {
.execute();
mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
+ homeActivity = mStackSupervisor.getHomeActivity();
+ display = homeActivity.getDisplay();
+
// TODO: Maybe wait for app to draw in this particular case?
}
- final ActivityRecord homeActivity = mStackSupervisor.getHomeActivity();
- final ActivityDisplay display = homeActivity.getDisplay();
-
- // Save the initial position of the home activity stack to be restored to after the
- // animation completes
- mRestoreHomeBehindStack = hasExistingHomeActivity
- ? display.getStackAboveHome()
- : null;
-
- // Move the home activity into place for the animation
- display.moveHomeStackBehindBottomMostVisibleStack();
-
// Mark the home activity as launch-behind to bump its visibility for the
// duration of the gesture that is driven by the recents component
homeActivity.mLaunchTaskBehind = true;
+ // Post a timeout for the animation. This needs to happen before initializing the
+ // recents animation on the WM side since we may decide to cancel the animation there
+ mHandler.postDelayed(mCancelAnimationRunnable, RECENTS_ANIMATION_TIMEOUT);
+
// Fetch all the surface controls and pass them to the client to get the animation
// started
mWindowManager.initializeRecentsAnimation(recentsAnimationRunner, this,
@@ -122,9 +140,6 @@ class RecentsAnimation implements RecentsAnimationCallbacks {
// If we updated the launch-behind state, update the visibility of the activities after
// we fetch the visible tasks to be controlled by the animation
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
-
- // Post a timeout for the animation
- mHandler.postDelayed(mCancelAnimationRunnable, RECENTS_ANIMATION_TIMEOUT);
} finally {
mWindowManager.continueSurfaceLayout();
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
@@ -178,4 +193,15 @@ class RecentsAnimation implements RecentsAnimationCallbacks {
});
}
}
+
+ /**
+ * Called only when the animation should be canceled prior to starting.
+ */
+ private void notifyAnimationCancelBeforeStart(IRecentsAnimationRunner recentsAnimationRunner) {
+ try {
+ recentsAnimationRunner.onAnimationCanceled();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to cancel recents animation before start", e);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/am/UriPermission.java
index 1e071aa3f5dc..3bf1cf487ca0 100644
--- a/services/core/java/com/android/server/am/UriPermission.java
+++ b/services/core/java/com/android/server/am/UriPermission.java
@@ -124,6 +124,10 @@ final class UriPermission {
updateModeFlags();
}
+ boolean isNew() {
+ return persistedCreateTime == INVALID_TIME;
+ }
+
void grantModes(int modeFlags, UriPermissionOwner owner) {
final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index e95608f16203..76e0d8984cb8 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -70,6 +70,7 @@ import android.media.AudioRoutesInfo;
import android.media.AudioSystem;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioRoutesObserver;
+import android.media.IAudioServerStateDispatcher;
import android.media.IAudioService;
import android.media.IPlaybackConfigDispatcher;
import android.media.IRecordingConfigDispatcher;
@@ -242,6 +243,7 @@ public class AudioService extends IAudioService.Stub
private static final int MSG_INDICATE_SYSTEM_READY = 26;
private static final int MSG_ACCESSORY_PLUG_MEDIA_UNMUTE = 27;
private static final int MSG_NOTIFY_VOL_EVENT = 28;
+ private static final int MSG_DISPATCH_AUDIO_SERVER_STATE = 29;
// start of messages handled under wakelock
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
// and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -390,6 +392,8 @@ public class AudioService extends IAudioService.Stub
case AudioSystem.AUDIO_STATUS_SERVER_DIED:
sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED,
SENDMSG_NOOP, 0, 0, null, 0);
+ sendMsg(mAudioHandler, MSG_DISPATCH_AUDIO_SERVER_STATE,
+ SENDMSG_QUEUE, 0, 0, null, 0);
break;
default:
break;
@@ -547,8 +551,6 @@ public class AudioService extends IAudioService.Stub
// Used to play ringtones outside system_server
private volatile IRingtonePlayer mRingtonePlayer;
- private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
-
// Request to override default use of A2DP for media.
private boolean mBluetoothA2dpEnabled;
private final Object mBluetoothA2dpEnabledLock = new Object();
@@ -567,8 +569,6 @@ public class AudioService extends IAudioService.Stub
AudioSystem.DEVICE_OUT_AUX_LINE;
int mFullVolumeDevices = 0;
- // TODO merge orientation and rotation
- private final boolean mMonitorOrientation;
private final boolean mMonitorRotation;
private boolean mDockAudioMediaEnabled = true;
@@ -784,13 +784,6 @@ public class AudioService extends IAudioService.Stub
intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- // TODO merge orientation and rotation
- mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
- if (mMonitorOrientation) {
- Log.v(TAG, "monitoring device orientation");
- // initialize orientation in AudioSystem
- setOrientationForAudioSystem();
- }
mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
if (mMonitorRotation) {
RotationHelper.init(mContext, mAudioHandler);
@@ -959,10 +952,7 @@ public class AudioService extends IAudioService.Stub
// Restore ringer mode
setRingerModeInt(getRingerModeInternal(), false);
- // Reset device orientation (if monitored for this device)
- if (mMonitorOrientation) {
- setOrientationForAudioSystem();
- }
+ // Reset device rotation (if monitored for this device)
if (mMonitorRotation) {
RotationHelper.updateOrientation();
}
@@ -1000,6 +990,21 @@ public class AudioService extends IAudioService.Stub
onIndicateSystemReady();
// indicate the end of reconfiguration phase to audio HAL
AudioSystem.setParameters("restarting=false");
+
+ sendMsg(mAudioHandler, MSG_DISPATCH_AUDIO_SERVER_STATE,
+ SENDMSG_QUEUE, 1, 0, null, 0);
+ }
+
+ private void onDispatchAudioServerStateChange(boolean state) {
+ synchronized (mAudioServerStateListeners) {
+ for (AsdProxy asdp : mAudioServerStateListeners.values()) {
+ try {
+ asdp.callback().dispatchAudioServerStateChange(state);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not call dispatchAudioServerStateChange()", e);
+ }
+ }
+ }
}
private void createAudioSystemThread() {
@@ -1023,14 +1028,16 @@ public class AudioService extends IAudioService.Stub
}
private void checkAllAliasStreamVolumes() {
- synchronized (VolumeStreamState.class) {
- int numStreamTypes = AudioSystem.getNumStreamTypes();
- for (int streamType = 0; streamType < numStreamTypes; streamType++) {
- mStreamStates[streamType]
- .setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], TAG);
- // apply stream volume
- if (!mStreamStates[streamType].mIsMuted) {
- mStreamStates[streamType].applyAllVolumes();
+ synchronized (mSettingsLock) {
+ synchronized (VolumeStreamState.class) {
+ int numStreamTypes = AudioSystem.getNumStreamTypes();
+ for (int streamType = 0; streamType < numStreamTypes; streamType++) {
+ mStreamStates[streamType]
+ .setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], TAG);
+ // apply stream volume
+ if (!mStreamStates[streamType].mIsMuted) {
+ mStreamStates[streamType].applyAllVolumes();
+ }
}
}
}
@@ -1136,13 +1143,16 @@ public class AudioService extends IAudioService.Stub
if (updateVolumes && mStreamStates != null) {
updateDefaultVolumes();
- mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
- caller);
-
- mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].mVolumeIndexSettingName =
- System.VOLUME_SETTINGS_INT[a11yStreamAlias];
- mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setAllIndexes(
- mStreamStates[a11yStreamAlias], caller);
+ synchronized (mSettingsLock) {
+ synchronized (VolumeStreamState.class) {
+ mStreamStates[AudioSystem.STREAM_DTMF]
+ .setAllIndexes(mStreamStates[dtmfStreamAlias], caller);
+ mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].mVolumeIndexSettingName =
+ System.VOLUME_SETTINGS_INT[a11yStreamAlias];
+ mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setAllIndexes(
+ mStreamStates[a11yStreamAlias], caller);
+ }
+ }
if (sIndependentA11yVolume) {
// restore the a11y values from the settings
mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].readSettings();
@@ -4585,39 +4595,36 @@ public class AudioService extends IAudioService.Stub
* @param srcStream
* @param caller
*/
+ // must be sync'd on mSettingsLock before VolumeStreamState.class
+ @GuardedBy("VolumeStreamState.class")
public void setAllIndexes(VolumeStreamState srcStream, String caller) {
if (mStreamType == srcStream.mStreamType) {
return;
}
- synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
- int srcStreamType = srcStream.getStreamType();
- // apply default device volume from source stream to all devices first in case
- // some devices are present in this stream state but not in source stream state
- int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
- index = rescaleIndex(index, srcStreamType, mStreamType);
- for (int i = 0; i < mIndexMap.size(); i++) {
- mIndexMap.put(mIndexMap.keyAt(i), index);
- }
- // Now apply actual volume for devices in source stream state
- SparseIntArray srcMap = srcStream.mIndexMap;
- for (int i = 0; i < srcMap.size(); i++) {
- int device = srcMap.keyAt(i);
- index = srcMap.valueAt(i);
- index = rescaleIndex(index, srcStreamType, mStreamType);
-
- setIndex(index, device, caller);
- }
- }
+ int srcStreamType = srcStream.getStreamType();
+ // apply default device volume from source stream to all devices first in case
+ // some devices are present in this stream state but not in source stream state
+ int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
+ index = rescaleIndex(index, srcStreamType, mStreamType);
+ for (int i = 0; i < mIndexMap.size(); i++) {
+ mIndexMap.put(mIndexMap.keyAt(i), index);
+ }
+ // Now apply actual volume for devices in source stream state
+ SparseIntArray srcMap = srcStream.mIndexMap;
+ for (int i = 0; i < srcMap.size(); i++) {
+ int device = srcMap.keyAt(i);
+ index = srcMap.valueAt(i);
+ index = rescaleIndex(index, srcStreamType, mStreamType);
+
+ setIndex(index, device, caller);
}
}
- @GuardedBy("mSettingsLock")
+ // must be sync'd on mSettingsLock before VolumeStreamState.class
+ @GuardedBy("VolumeStreamState.class")
public void setAllIndexesToMax() {
- synchronized (VolumeStreamState.class) {
- for (int i = 0; i < mIndexMap.size(); i++) {
- mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
- }
+ for (int i = 0; i < mIndexMap.size(); i++) {
+ mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
}
}
@@ -5089,6 +5096,10 @@ public class AudioService extends IAudioService.Stub
onAudioServerDied();
break;
+ case MSG_DISPATCH_AUDIO_SERVER_STATE:
+ onDispatchAudioServerStateChange(msg.arg1 == 1);
+ break;
+
case MSG_UNLOAD_SOUND_EFFECTS:
onUnloadSoundEffects();
break;
@@ -6169,24 +6180,15 @@ public class AudioService extends IAudioService.Stub
// Device orientation
//==========================================================================================
/**
- * Handles device configuration changes that may map to a change in the orientation
- * or orientation.
- * Monitoring orientation and rotation is optional, and is defined by the definition and value
- * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
+ * Handles device configuration changes that may map to a change in rotation.
+ * Monitoring rotation is optional, and is defined by the definition and value
+ * of the "ro.audio.monitorRotation" system property.
*/
private void handleConfigurationChanged(Context context) {
try {
- // reading new orientation "safely" (i.e. under try catch) in case anything
- // goes wrong when obtaining resources and configuration
+ // reading new configuration "safely" (i.e. under try catch) in case anything
+ // goes wrong.
Configuration config = context.getResources().getConfiguration();
- // TODO merge rotation and orientation
- if (mMonitorOrientation) {
- int newOrientation = config.orientation;
- if (newOrientation != mDeviceOrientation) {
- mDeviceOrientation = newOrientation;
- setOrientationForAudioSystem();
- }
- }
sendMsg(mAudioHandler,
MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
SENDMSG_REPLACE,
@@ -6201,15 +6203,17 @@ public class AudioService extends IAudioService.Stub
mCameraSoundForced = cameraSoundForced;
if (cameraSoundForcedChanged) {
if (!mIsSingleVolume) {
- VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
- if (cameraSoundForced) {
- s.setAllIndexesToMax();
- mRingerModeAffectedStreams &=
- ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
- } else {
- s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG);
- mRingerModeAffectedStreams |=
- (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+ synchronized (VolumeStreamState.class) {
+ VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
+ if (cameraSoundForced) {
+ s.setAllIndexesToMax();
+ mRingerModeAffectedStreams &=
+ ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+ } else {
+ s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG);
+ mRingerModeAffectedStreams |=
+ (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+ }
}
// take new state into account for streams muted by ringer mode
setRingerModeInt(getRingerModeInternal(), false);
@@ -6238,30 +6242,6 @@ public class AudioService extends IAudioService.Stub
}
}
- //TODO move to an external "orientation helper" class
- private void setOrientationForAudioSystem() {
- switch (mDeviceOrientation) {
- case Configuration.ORIENTATION_LANDSCAPE:
- //Log.i(TAG, "orientation is landscape");
- AudioSystem.setParameters("orientation=landscape");
- break;
- case Configuration.ORIENTATION_PORTRAIT:
- //Log.i(TAG, "orientation is portrait");
- AudioSystem.setParameters("orientation=portrait");
- break;
- case Configuration.ORIENTATION_SQUARE:
- //Log.i(TAG, "orientation is square");
- AudioSystem.setParameters("orientation=square");
- break;
- case Configuration.ORIENTATION_UNDEFINED:
- //Log.i(TAG, "orientation is undefined");
- AudioSystem.setParameters("orientation=undefined");
- break;
- default:
- Log.e(TAG, "Unknown orientation");
- }
- }
-
// Handles request to override default use of A2DP for media.
// Must be called synchronized on mConnectedDevices
public void setBluetoothA2dpOnInt(boolean on, String eventSource) {
@@ -7341,6 +7321,77 @@ public class AudioService extends IAudioService.Stub
//======================
+ // Audioserver state displatch
+ //======================
+ private class AsdProxy implements IBinder.DeathRecipient {
+ private final IAudioServerStateDispatcher mAsd;
+
+ AsdProxy(IAudioServerStateDispatcher asd) {
+ mAsd = asd;
+ }
+
+ public void binderDied() {
+ synchronized (mAudioServerStateListeners) {
+ mAudioServerStateListeners.remove(mAsd.asBinder());
+ }
+ }
+
+ IAudioServerStateDispatcher callback() {
+ return mAsd;
+ }
+ }
+
+ private HashMap<IBinder, AsdProxy> mAudioServerStateListeners =
+ new HashMap<IBinder, AsdProxy>();
+
+ private void checkMonitorAudioServerStatePermission() {
+ if (!(mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.MODIFY_PHONE_STATE) ==
+ PackageManager.PERMISSION_GRANTED ||
+ mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.MODIFY_AUDIO_ROUTING) ==
+ PackageManager.PERMISSION_GRANTED)) {
+ throw new SecurityException("Not allowed to monitor audioserver state");
+ }
+ }
+
+ public void registerAudioServerStateDispatcher(IAudioServerStateDispatcher asd) {
+ checkMonitorAudioServerStatePermission();
+ synchronized (mAudioServerStateListeners) {
+ if (mAudioServerStateListeners.containsKey(asd.asBinder())) {
+ Slog.w(TAG, "Cannot re-register audio server state dispatcher");
+ return;
+ }
+ AsdProxy asdp = new AsdProxy(asd);
+ try {
+ asd.asBinder().linkToDeath(asdp, 0/*flags*/);
+ } catch (RemoteException e) {
+
+ }
+ mAudioServerStateListeners.put(asd.asBinder(), asdp);
+ }
+ }
+
+ public void unregisterAudioServerStateDispatcher(IAudioServerStateDispatcher asd) {
+ checkMonitorAudioServerStatePermission();
+ synchronized (mAudioServerStateListeners) {
+ AsdProxy asdp = mAudioServerStateListeners.remove(asd.asBinder());
+ if (asdp == null) {
+ Slog.w(TAG, "Trying to unregister unknown audioserver state dispatcher for pid "
+ + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
+ return;
+ } else {
+ asd.asBinder().unlinkToDeath(asdp, 0/*flags*/);
+ }
+ }
+ }
+
+ public boolean isAudioServerRunning() {
+ checkMonitorAudioServerStatePermission();
+ return (AudioSystem.checkAudioFlinger() == AudioSystem.AUDIO_STATUS_OK);
+ }
+
+ //======================
// misc
//======================
private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
diff --git a/services/core/java/com/android/server/audio/OWNERS b/services/core/java/com/android/server/audio/OWNERS
new file mode 100644
index 000000000000..b70de299eeea
--- /dev/null
+++ b/services/core/java/com/android/server/audio/OWNERS
@@ -0,0 +1,2 @@
+jmtrivi@google.com
+elaurent@google.com
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 85b70ca0ffcd..a24f97e53570 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -392,6 +392,15 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
return !isVPN() && numForegroundNetworkRequests() == 0 && mNumBackgroundNetworkRequests > 0;
}
+ /**
+ * Returns whether this network is currently suspended. A network is suspended if it is still
+ * connected but data temporarily fails to transfer. See {@link NetworkInfo.State#SUSPENDED}
+ * and {@link NetworkCapabilities#NET_CAPABILITY_NOT_SUSPENDED}.
+ */
+ public boolean isSuspended() {
+ return networkInfo.getState() == NetworkInfo.State.SUSPENDED;
+ }
+
// Does this network satisfy request?
public boolean satisfies(NetworkRequest request) {
return created &&
@@ -458,7 +467,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
public NetworkState getNetworkState() {
synchronized (this) {
- // Network objects are outwardly immutable so there is no point to duplicating.
+ // Network objects are outwardly immutable so there is no point in duplicating.
// Duplicating also precludes sharing socket factories and connection pools.
final String subscriberId = (networkMisc != null) ? networkMisc.subscriberId : null;
return new NetworkState(new NetworkInfo(networkInfo),
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index c3f020ade635..63308f894d09 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -97,9 +97,7 @@ public final class ContentService extends IContentService.Stub {
@Override
public void onBootPhase(int phase) {
- if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
- mService.systemReady();
- }
+ mService.onBootPhase(phase);
}
@@ -300,8 +298,15 @@ public final class ContentService extends IContentService.Stub {
localeFilter, null, null);
}
- void systemReady() {
- getSyncManager();
+ void onBootPhase(int phase) {
+ switch (phase) {
+ case SystemService.PHASE_ACTIVITY_MANAGER_READY:
+ getSyncManager();
+ break;
+ }
+ if (mSyncManager != null) {
+ mSyncManager.onBootPhase(phase);
+ }
}
/**
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index de17ec782be4..70892685d8b4 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -89,6 +89,7 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
+import com.android.server.SystemService;
import com.android.server.job.JobSchedulerInternal;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
@@ -102,7 +103,6 @@ import com.android.server.backup.AccountSyncSettingsBackupHelper;
import com.android.server.content.SyncStorageEngine.AuthorityInfo;
import com.android.server.content.SyncStorageEngine.EndPoint;
import com.android.server.content.SyncStorageEngine.OnSyncRequestListener;
-import com.android.server.job.JobSchedulerInternal.JobStorePersistStats;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -158,18 +158,6 @@ public class SyncManager {
}
/**
- * When retrying a sync for the first time use this delay. After that
- * the retry time will double until it reached MAX_SYNC_RETRY_TIME.
- * In milliseconds.
- */
- private static final long INITIAL_SYNC_RETRY_TIME_IN_MS = 30 * 1000; // 30 seconds
-
- /**
- * Default the max sync retry time to this value.
- */
- private static final long DEFAULT_MAX_SYNC_RETRY_TIME_IN_SECONDS = 60 * 60; // one hour
-
- /**
* How long to wait before retrying a sync that failed due to one already being in progress.
*/
private static final int DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS = 10;
@@ -449,6 +437,7 @@ public class SyncManager {
};
private final SyncHandler mSyncHandler;
+ private final SyncManagerConstants mConstants;
private volatile boolean mBootCompleted = false;
private volatile boolean mJobServiceReady = false;
@@ -616,6 +605,7 @@ public class SyncManager {
}, mSyncHandler);
mRand = new Random(System.currentTimeMillis());
+ mConstants = new SyncManagerConstants(context);
IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(mConnectivityIntentReceiver, intentFilter);
@@ -756,6 +746,14 @@ public class SyncManager {
mSyncHandler.post(() -> mLogger.log("onStopUser: user=", userHandle));
}
+ public void onBootPhase(int phase) {
+ // Note SyncManager only receives PHASE_ACTIVITY_MANAGER_READY and after.
+ switch (phase) {
+ case SystemService.PHASE_ACTIVITY_MANAGER_READY:
+ mConstants.start();
+ break;
+ }
+ }
private void whiteListExistingSyncAdaptersIfNeeded() {
if (!mSyncStorageEngine.shouldGrantSyncAdaptersAccountAccess()) {
@@ -903,7 +901,10 @@ public class SyncManager {
}
if (isLoggable) {
Log.d(TAG, "one-time sync for: " + requestedAccount + " " + extras.toString() + " "
- + requestedAuthority);
+ + requestedAuthority
+ + " reason=" + reason
+ + " checkIfAccountReady=" + checkIfAccountReady
+ + " isAppStandbyExempted=" + isAppStandbyExempted);
}
AccountAndUser[] accounts = null;
@@ -1368,18 +1369,18 @@ public class SyncManager {
return;
}
// Subsequent delays are the double of the previous delay.
- newDelayInMs = previousSettings.second * 2;
+ newDelayInMs =
+ (long) (previousSettings.second * mConstants.getRetryTimeIncreaseFactor());
}
if (newDelayInMs <= 0) {
// The initial delay is the jitterized INITIAL_SYNC_RETRY_TIME_IN_MS.
- newDelayInMs = jitterize(INITIAL_SYNC_RETRY_TIME_IN_MS,
- (long)(INITIAL_SYNC_RETRY_TIME_IN_MS * 1.1));
+ final long initialRetryMs = mConstants.getInitialSyncRetryTimeInSeconds() * 1000;
+ newDelayInMs = jitterize(initialRetryMs, (long)(initialRetryMs * 1.1));
}
// Cap the delay.
- long maxSyncRetryTimeInSeconds = Settings.Global.getLong(mContext.getContentResolver(),
- Settings.Global.SYNC_MAX_RETRY_DELAY_IN_SECONDS,
- DEFAULT_MAX_SYNC_RETRY_TIME_IN_SECONDS);
+ final long maxSyncRetryTimeInSeconds = mConstants.getMaxSyncRetryTimeInSeconds();
+
if (newDelayInMs > maxSyncRetryTimeInSeconds * 1000) {
newDelayInMs = maxSyncRetryTimeInSeconds * 1000;
}
@@ -1930,6 +1931,7 @@ public class SyncManager {
protected void dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
dumpSyncState(ipw);
+ mConstants.dump(pw, "");
dumpSyncAdapters(ipw);
if (dumpAll) {
@@ -2076,8 +2078,33 @@ public class SyncManager {
protected void dumpSyncState(PrintWriter pw) {
final StringBuilder sb = new StringBuilder();
- pw.print("data connected: "); pw.println(mDataConnectionIsConnected);
- pw.print("auto sync: ");
+ pw.print("Data connected: "); pw.println(mDataConnectionIsConnected);
+ pw.print("Battery saver: ");
+ pw.println((mPowerManager != null) && mPowerManager.isPowerSaveMode());
+
+ pw.print("Background network restriction: ");
+ {
+ final ConnectivityManager cm = getConnectivityManager();
+ final int status = (cm == null) ? -1 : cm.getRestrictBackgroundStatus();
+ switch (status) {
+ case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED:
+ pw.println(" disabled");
+ break;
+ case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED:
+ pw.println(" whitelisted");
+ break;
+ case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED:
+ pw.println(" enabled");
+ break;
+ default:
+ pw.print("Unknown(");
+ pw.print(status);
+ pw.println(")");
+ break;
+ }
+ }
+
+ pw.print("Auto sync: ");
List<UserInfo> users = getAllUsers();
if (users != null) {
for (UserInfo user : users) {
@@ -2086,26 +2113,26 @@ public class SyncManager {
}
pw.println();
}
- pw.print("memory low: "); pw.println(mStorageIsLow);
- pw.print("device idle: "); pw.println(mDeviceIsIdle);
- pw.print("reported active: "); pw.println(mReportedSyncActive);
+ pw.print("Memory low: "); pw.println(mStorageIsLow);
+ pw.print("Device idle: "); pw.println(mDeviceIsIdle);
+ pw.print("Reported active: "); pw.println(mReportedSyncActive);
final AccountAndUser[] accounts = AccountManagerService.getSingleton().getAllAccounts();
- pw.print("accounts: ");
+ pw.print("Accounts: ");
if (accounts != INITIAL_ACCOUNTS_ARRAY) {
pw.println(accounts.length);
} else {
pw.println("not known yet");
}
final long now = SystemClock.elapsedRealtime();
- pw.print("now: "); pw.print(now);
+ pw.print("Now: "); pw.print(now);
pw.println(" (" + formatTime(System.currentTimeMillis()) + ")");
sb.setLength(0);
- pw.print("uptime: "); pw.print(formatDurationHMS(sb, now));
+ pw.print("Uptime: "); pw.print(formatDurationHMS(sb, now));
pw.println();
- pw.print("time spent syncing: ");
+ pw.print("Time spent syncing: ");
sb.setLength(0);
pw.print(formatDurationHMS(sb,
@@ -3573,7 +3600,13 @@ public class SyncManager {
reschedulePeriodicSyncH(syncOperation);
}
} else {
- Log.d(TAG, "failed sync operation " + syncOperation + ", " + syncResult);
+ Log.w(TAG, "failed sync operation " + syncOperation + ", " + syncResult);
+
+ syncOperation.retries++;
+ if (syncOperation.retries > mConstants.getMaxRetriesWithAppStandbyExemption()) {
+ syncOperation.isAppStandbyExempted = false;
+ }
+
// the operation failed so increase the backoff time
increaseBackoffSetting(syncOperation.target);
if (!syncOperation.isPeriodic) {
diff --git a/services/core/java/com/android/server/content/SyncManagerConstants.java b/services/core/java/com/android/server/content/SyncManagerConstants.java
new file mode 100644
index 000000000000..061e4ca02d2d
--- /dev/null
+++ b/services/core/java/com/android/server/content/SyncManagerConstants.java
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+package com.android.server.content;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.util.KeyValueListParser;
+import android.util.Slog;
+
+import com.android.internal.os.BackgroundThread;
+
+import java.io.PrintWriter;
+
+public class SyncManagerConstants extends ContentObserver {
+ private static final String TAG = "SyncManagerConfig";
+
+ private final Object mLock = new Object();
+ private final Context mContext;
+
+ private static final String KEY_INITIAL_SYNC_RETRY_TIME_IN_SECONDS =
+ "initial_sync_retry_time_in_seconds";
+ private static final int DEF_INITIAL_SYNC_RETRY_TIME_IN_SECONDS = 30;
+ private int mInitialSyncRetryTimeInSeconds = DEF_INITIAL_SYNC_RETRY_TIME_IN_SECONDS;
+
+ private static final String KEY_RETRY_TIME_INCREASE_FACTOR =
+ "retry_time_increase_factor";
+ private static final float DEF_RETRY_TIME_INCREASE_FACTOR = 2.0f;
+ private float mRetryTimeIncreaseFactor = DEF_RETRY_TIME_INCREASE_FACTOR;
+
+ private static final String KEY_MAX_SYNC_RETRY_TIME_IN_SECONDS =
+ "max_sync_retry_time_in_seconds";
+ private static final int DEF_MAX_SYNC_RETRY_TIME_IN_SECONDS = 60 * 60;
+ private int mMaxSyncRetryTimeInSeconds = DEF_MAX_SYNC_RETRY_TIME_IN_SECONDS;
+
+ private static final String KEY_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION =
+ "max_retries_with_app_standby_exemption";
+ private static final int DEF_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION = 5;
+ private int mMaxRetriesWithAppStandbyExemption = DEF_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION;
+
+ protected SyncManagerConstants(Context context) {
+ super(null);
+ mContext = context;
+ }
+
+ public void start() {
+ BackgroundThread.getHandler().post(() -> {
+ mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.SYNC_MANAGER_CONSTANTS), false, this);
+ refresh();
+ });
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ refresh();
+ }
+
+ private void refresh() {
+ synchronized (mLock) {
+
+ String newValue = Settings.Global.getString(mContext.getContentResolver(),
+ Global.SYNC_MANAGER_CONSTANTS);
+ final KeyValueListParser parser = new KeyValueListParser(',');
+ try {
+ parser.setString(newValue);
+ } catch (IllegalArgumentException e) {
+ Slog.wtf(TAG, "Bad constants: " + newValue);
+ }
+
+ mInitialSyncRetryTimeInSeconds = parser.getInt(
+ KEY_INITIAL_SYNC_RETRY_TIME_IN_SECONDS,
+ DEF_INITIAL_SYNC_RETRY_TIME_IN_SECONDS);
+
+ mMaxSyncRetryTimeInSeconds = parser.getInt(
+ KEY_MAX_SYNC_RETRY_TIME_IN_SECONDS,
+ DEF_MAX_SYNC_RETRY_TIME_IN_SECONDS);
+
+ mRetryTimeIncreaseFactor = parser.getFloat(
+ KEY_RETRY_TIME_INCREASE_FACTOR,
+ DEF_RETRY_TIME_INCREASE_FACTOR);
+
+ mMaxRetriesWithAppStandbyExemption = parser.getInt(
+ KEY_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION,
+ DEF_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION);
+ }
+ }
+
+ public int getInitialSyncRetryTimeInSeconds() {
+ synchronized (mLock) {
+ return mInitialSyncRetryTimeInSeconds;
+ }
+ }
+
+ public float getRetryTimeIncreaseFactor() {
+ synchronized (mLock) {
+ return mRetryTimeIncreaseFactor;
+ }
+ }
+
+ public int getMaxSyncRetryTimeInSeconds() {
+ synchronized (mLock) {
+ return mMaxSyncRetryTimeInSeconds;
+ }
+ }
+
+ public int getMaxRetriesWithAppStandbyExemption() {
+ synchronized (mLock) {
+ return mMaxRetriesWithAppStandbyExemption;
+ }
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ synchronized (mLock) {
+ pw.print(prefix);
+ pw.println("SyncManager Config:");
+
+ pw.print(prefix);
+ pw.print(" mInitialSyncRetryTimeInSeconds=");
+ pw.println(mInitialSyncRetryTimeInSeconds);
+
+ pw.print(prefix);
+ pw.print(" mRetryTimeIncreaseFactor=");
+ pw.println(mRetryTimeIncreaseFactor);
+
+ pw.print(prefix);
+ pw.print(" mMaxSyncRetryTimeInSeconds=");
+ pw.println(mMaxSyncRetryTimeInSeconds);
+
+ pw.print(prefix);
+ pw.print(" mMaxRetriesWithAppStandbyExemption=");
+ pw.println(mMaxRetriesWithAppStandbyExemption);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index f6b481920faf..96bdaeabf17c 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -408,6 +408,10 @@ public class SyncOperation {
extrasToStringBuilder(extras, sb);
}
}
+ if (retries > 0) {
+ sb.append(" Retries=");
+ sb.append(retries);
+ }
return sb.toString();
}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index b5f94b1ce384..692535c6cebc 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -421,7 +421,7 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
byteToken[i] = token.get(i);
}
// Send to Keystore
- KeyStore.getInstance().addAuthToken(byteToken);
+ KeyStore.getInstance().addAuthToken(byteToken, mCurrentUserId);
}
if (client != null && client.onAuthenticated(fingerId, groupId)) {
removeClient(client);
@@ -915,7 +915,7 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
notifyLockoutResetMonitors();
}
- private class FingerprintServiceLockoutResetMonitor {
+ private class FingerprintServiceLockoutResetMonitor implements IBinder.DeathRecipient {
private static final long WAKELOCK_TIMEOUT_MS = 2000;
private final IFingerprintServiceLockoutResetCallback mCallback;
@@ -926,6 +926,11 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
mCallback = callback;
mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"lockout reset callback");
+ try {
+ mCallback.asBinder().linkToDeath(FingerprintServiceLockoutResetMonitor.this, 0);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "caught remote exception in linkToDeath", e);
+ }
}
public void sendLockoutReset() {
@@ -959,6 +964,12 @@ public class FingerprintService extends SystemService implements IHwBinder.Death
removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this);
}
};
+
+ @Override
+ public void binderDied() {
+ Slog.e(TAG, "Lockout reset callback binder died");
+ mHandler.post(mRemoveCallbackRunnable);
+ }
}
private IBiometricsFingerprintClientCallback mDaemonCallback =
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index e5f4282eefe0..0cba76ba7346 100644..100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -660,7 +660,8 @@ abstract class HdmiCecLocalDevice {
@ServiceThreadOnly
void startQueuedActions() {
assertRunOnServiceThread();
- for (HdmiCecFeatureAction action : mActions) {
+ // Use copied action list in that start() may remove itself.
+ for (HdmiCecFeatureAction action : new ArrayList<>(mActions)) {
if (!action.started()) {
Slog.i(TAG, "Starting queued action:" + action);
action.start();
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index be48f69e1545..c33d7f4b4451 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -23,6 +23,7 @@ import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
+import android.app.AlarmManager;
import android.app.AppGlobals;
import android.app.IUidObserver;
import android.app.job.IJobScheduler;
@@ -184,6 +185,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
IBatteryStats mBatteryStats;
DeviceIdleController.LocalService mLocalDeviceIdleController;
AppStateTracker mAppStateTracker;
+ final UsageStatsManagerInternal mUsageStats;
/**
* Set to true once we are allowed to run third party apps.
@@ -225,7 +227,10 @@ public final class JobSchedulerService extends com.android.server.SystemService
*/
final long[] mNextBucketHeartbeat = { 0, 0, 0, 0, Long.MAX_VALUE };
long mHeartbeat = 0;
- long mLastHeartbeatTime = 0;
+ long mLastHeartbeatTime = sElapsedRealtimeClock.millis();
+
+ static final String HEARTBEAT_TAG = "*job.heartbeat*";
+ final HeartbeatAlarmListener mHeartbeatAlarm = new HeartbeatAlarmListener();
// -- Pre-allocated temporaries only for use in assignJobsToContextsLocked --
@@ -495,6 +500,9 @@ public final class JobSchedulerService extends com.android.server.SystemService
STANDBY_BEATS[3] = mParser.getInt(KEY_STANDBY_RARE_BEATS,
DEFAULT_STANDBY_RARE_BEATS);
}
+
+ // Reset the heartbeat alarm based on the new heartbeat duration
+ setNextHeartbeatAlarm();
}
void dump(PrintWriter pw) {
@@ -1090,9 +1098,9 @@ public final class JobSchedulerService extends com.android.server.SystemService
mJobSchedulerStub = new JobSchedulerStub();
// Set up the app standby bucketing tracker
- UsageStatsManagerInternal usageStats = LocalServices.getService(UsageStatsManagerInternal.class);
- mStandbyTracker = new StandbyTracker(usageStats);
- usageStats.addAppIdleStateChangeListener(mStandbyTracker);
+ mStandbyTracker = new StandbyTracker();
+ mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
+ mUsageStats.addAppIdleStateChangeListener(mStandbyTracker);
// The job store needs to call back
publishLocalService(JobSchedulerInternal.class, new LocalService());
@@ -1177,6 +1185,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
mAppStateTracker = Preconditions.checkNotNull(
LocalServices.getService(AppStateTracker.class));
+ setNextHeartbeatAlarm();
// Register br for package removals and user removals.
final IntentFilter filter = new IntentFilter();
@@ -1418,6 +1427,23 @@ public final class JobSchedulerService extends com.android.server.SystemService
periodicToReschedule.getLastFailedRunTime());
}
+ long heartbeatWhenJobsLastRun(String packageName, final @UserIdInt int userId) {
+ final long heartbeat;
+ final long timeSinceLastJob = mUsageStats.getTimeSinceLastJobRun(packageName, userId);
+ synchronized (mLock) {
+ heartbeat = mHeartbeat - (timeSinceLastJob / mConstants.STANDBY_HEARTBEAT_TIME);
+ }
+ if (DEBUG_STANDBY) {
+ Slog.v(TAG, "Last job heartbeat " + heartbeat + " for " + packageName + "/" + userId
+ + " delta=" + timeSinceLastJob);
+ }
+ return heartbeat;
+ }
+
+ long heartbeatWhenJobsLastRun(JobStatus job) {
+ return heartbeatWhenJobsLastRun(job.getSourcePackageName(), job.getSourceUserId());
+ }
+
// JobCompletedListener implementations.
/**
@@ -1560,9 +1586,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
noteJobsNonpending(mPendingJobs);
mPendingJobs.clear();
stopNonReadyActiveJobsLocked();
- boolean updated = updateStandbyHeartbeatLocked();
mJobs.forEachJob(mReadyQueueFunctor);
- if (updated) updateNextStandbyHeartbeatsLocked();
mReadyQueueFunctor.postProcess();
if (DEBUG) {
@@ -1716,38 +1740,80 @@ public final class JobSchedulerService extends com.android.server.SystemService
noteJobsNonpending(mPendingJobs);
mPendingJobs.clear();
stopNonReadyActiveJobsLocked();
- boolean updated = updateStandbyHeartbeatLocked();
mJobs.forEachJob(mMaybeQueueFunctor);
- if (updated) updateNextStandbyHeartbeatsLocked();
mMaybeQueueFunctor.postProcess();
}
- private boolean updateStandbyHeartbeatLocked() {
- final long sinceLast = sElapsedRealtimeClock.millis() - mLastHeartbeatTime;
- final long beatsElapsed = sinceLast / mConstants.STANDBY_HEARTBEAT_TIME;
- if (beatsElapsed > 0) {
- mHeartbeat += beatsElapsed;
- mLastHeartbeatTime += beatsElapsed * mConstants.STANDBY_HEARTBEAT_TIME;
- if (DEBUG_STANDBY) {
- Slog.v(TAG, "Advancing standby heartbeat by " + beatsElapsed + " to " + mHeartbeat);
+ /**
+ * Heartbeat tracking. The heartbeat alarm is intentionally non-wakeup.
+ */
+ class HeartbeatAlarmListener implements AlarmManager.OnAlarmListener {
+
+ @Override
+ public void onAlarm() {
+ synchronized (mLock) {
+ final long sinceLast = sElapsedRealtimeClock.millis() - mLastHeartbeatTime;
+ final long beatsElapsed = sinceLast / mConstants.STANDBY_HEARTBEAT_TIME;
+ if (beatsElapsed > 0) {
+ mLastHeartbeatTime += beatsElapsed * mConstants.STANDBY_HEARTBEAT_TIME;
+ advanceHeartbeatLocked(beatsElapsed);
+ }
}
- return true;
+ setNextHeartbeatAlarm();
}
- return false;
}
- private void updateNextStandbyHeartbeatsLocked() {
- // don't update ACTIVE or NEVER bucket milestones
+ // Intentionally does not touch the alarm timing
+ void advanceHeartbeatLocked(long beatsElapsed) {
+ mHeartbeat += beatsElapsed;
+ if (DEBUG_STANDBY) {
+ Slog.v(TAG, "Advancing standby heartbeat by " + beatsElapsed
+ + " to " + mHeartbeat);
+ }
+ // Don't update ACTIVE or NEVER bucket milestones. Note that mHeartbeat
+ // will be equal to mNextBucketHeartbeat[bucket] for one beat, during which
+ // new jobs scheduled by apps in that bucket will be permitted to run
+ // immediately.
+ boolean didAdvanceBucket = false;
for (int i = 1; i < mNextBucketHeartbeat.length - 1; i++) {
- while (mHeartbeat >= mNextBucketHeartbeat[i]) {
+ // Did we reach or cross a bucket boundary?
+ if (mHeartbeat >= mNextBucketHeartbeat[i]) {
+ didAdvanceBucket = true;
+ }
+ while (mHeartbeat > mNextBucketHeartbeat[i]) {
mNextBucketHeartbeat[i] += mConstants.STANDBY_BEATS[i];
}
if (DEBUG_STANDBY) {
- Slog.v(TAG, " Bucket " + i + " next heartbeat " + mNextBucketHeartbeat[i]);
+ Slog.v(TAG, " Bucket " + i + " next heartbeat "
+ + mNextBucketHeartbeat[i]);
+ }
+ }
+
+ if (didAdvanceBucket) {
+ if (DEBUG_STANDBY) {
+ Slog.v(TAG, "Hit bucket boundary; reevaluating job runnability");
}
+ mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}
}
+ void setNextHeartbeatAlarm() {
+ final long heartbeatLength;
+ synchronized (mLock) {
+ heartbeatLength = mConstants.STANDBY_HEARTBEAT_TIME;
+ }
+ final long now = sElapsedRealtimeClock.millis();
+ final long nextBeatOrdinal = (now + heartbeatLength) / heartbeatLength;
+ final long nextHeartbeat = nextBeatOrdinal * heartbeatLength;
+ if (DEBUG_STANDBY) {
+ Slog.i(TAG, "Setting heartbeat alarm for " + nextHeartbeat
+ + " = " + TimeUtils.formatDuration(nextHeartbeat - now));
+ }
+ AlarmManager am = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
+ am.setExact(AlarmManager.ELAPSED_REALTIME, nextHeartbeat,
+ HEARTBEAT_TAG, mHeartbeatAlarm, mHandler);
+ }
+
/**
* Criteria for moving a job into the pending queue:
* - It's ready.
@@ -1811,17 +1877,20 @@ public final class JobSchedulerService extends com.android.server.SystemService
if (!mInParole && !job.getJob().isExemptedFromAppStandby()) {
final int bucket = job.getStandbyBucket();
if (mHeartbeat < mNextBucketHeartbeat[bucket]) {
- // Only skip this job if it's still waiting for the end of its (initial) nominal
+ // Only skip this job if the app is still waiting for the end of its nominal
// bucket interval. Once it's waited that long, we let it go ahead and clear.
// The final (NEVER) bucket is special; we never age those apps' jobs into
// runnability.
+ final long appLastRan = heartbeatWhenJobsLastRun(job);
if (bucket >= mConstants.STANDBY_BEATS.length
- || (mHeartbeat < job.getBaseHeartbeat() + mConstants.STANDBY_BEATS[bucket])) {
+ || (mHeartbeat > appLastRan
+ && mHeartbeat < appLastRan + mConstants.STANDBY_BEATS[bucket])) {
// TODO: log/trace that we're deferring the job due to bucketing if we hit this
if (job.getWhenStandbyDeferred() == 0) {
if (DEBUG_STANDBY) {
Slog.v(TAG, "Bucket deferral: " + mHeartbeat + " < "
- + mNextBucketHeartbeat[job.getStandbyBucket()] + " for " + job);
+ + (appLastRan + mConstants.STANDBY_BEATS[bucket])
+ + " for " + job);
}
job.setWhenStandbyDeferred(sElapsedRealtimeClock.millis());
}
@@ -2078,18 +2147,19 @@ public final class JobSchedulerService extends com.android.server.SystemService
// ACTIVE => everything can be run right away
// NEVER => we won't run them anyway, so let them go in the future
// as soon as the app enters normal use
+ if (DEBUG_STANDBY) {
+ Slog.v(TAG, "Base heartbeat forced ZERO for new job in "
+ + packageName + "/" + userId);
+ }
return 0;
}
- final long timeSinceLastJob = mStandbyTracker.getTimeSinceLastJobRun(
- packageName, userId);
- final long bucketLength = mConstants.STANDBY_BEATS[appStandbyBucket];
- final long bucketsAgo = timeSinceLastJob / bucketLength;
-
- // If we haven't run any jobs for more than the app's current bucket period, just
- // consider anything new to be immediately runnable. Otherwise, base it on the
- // bucket at which we last ran jobs.
- return (bucketsAgo > bucketLength) ? 0 : (getCurrentHeartbeat() - bucketsAgo);
+ final long baseHeartbeat = heartbeatWhenJobsLastRun(packageName, userId);
+ if (DEBUG_STANDBY) {
+ Slog.v(TAG, "Base heartbeat " + baseHeartbeat + " for new job in "
+ + packageName + "/" + userId);
+ }
+ return baseHeartbeat;
}
/**
@@ -2166,15 +2236,6 @@ public final class JobSchedulerService extends com.android.server.SystemService
* Tracking of app assignments to standby buckets
*/
final class StandbyTracker extends AppIdleStateChangeListener {
- final UsageStatsManagerInternal mUsageStats;
-
- StandbyTracker(UsageStatsManagerInternal usageStats) {
- mUsageStats = usageStats;
- }
-
- public long getTimeSinceLastJobRun(String packageName, final @UserIdInt int userId) {
- return mUsageStats.getTimeSinceLastJobRun(packageName, userId);
- }
// AppIdleStateChangeListener interface for live updates
@@ -2256,6 +2317,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
else return 0;
}
+ // Static to support external callers
public static int standbyBucketForPackage(String packageName, int userId, long elapsedNow) {
UsageStatsManagerInternal usageStats = LocalServices.getService(
UsageStatsManagerInternal.class);
@@ -2682,6 +2744,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
}
}
+ // Shell command infrastructure
int getJobState(PrintWriter pw, String pkgName, int userId, int jobId) {
try {
final int uid = AppGlobals.getPackageManager().getPackageUid(pkgName, 0,
@@ -2759,6 +2822,21 @@ public final class JobSchedulerService extends com.android.server.SystemService
return 0;
}
+ // Shell command infrastructure
+ int executeHeartbeatCommand(PrintWriter pw, int numBeats) {
+ if (numBeats < 1) {
+ pw.println(getCurrentHeartbeat());
+ return 0;
+ }
+
+ pw.print("Advancing standby heartbeat by ");
+ pw.println(numBeats);
+ synchronized (mLock) {
+ advanceHeartbeatLocked(numBeats);
+ }
+ return 0;
+ }
+
private String printContextIdToJobMap(JobStatus[] map, String initial) {
StringBuilder s = new StringBuilder(initial + ": ");
for (int i=0; i<map.length; i++) {
diff --git a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
index d630aab61ce5..63225f34234f 100644
--- a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
+++ b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -64,6 +64,8 @@ public final class JobSchedulerShellCommand extends ShellCommand {
return getStorageNotLow(pw);
case "get-job-state":
return getJobState(pw);
+ case "heartbeat":
+ return doHeartbeat(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -333,6 +335,20 @@ public final class JobSchedulerShellCommand extends ShellCommand {
}
}
+ private int doHeartbeat(PrintWriter pw) throws Exception {
+ checkPermission("manipulate scheduler heartbeat");
+
+ final String arg = getNextArg();
+ final int numBeats = (arg != null) ? Integer.parseInt(arg) : 0;
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return mInternal.executeHeartbeatCommand(pw, numBeats);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
@@ -359,6 +375,9 @@ public final class JobSchedulerShellCommand extends ShellCommand {
pw.println(" Options:");
pw.println(" -u or --user: specify which user's job is to be run; the default is");
pw.println(" the primary or system user");
+ pw.println(" heartbeat [num]");
+ pw.println(" With no argument, prints the current standby heartbeat. With a positive");
+ pw.println(" argument, advances the standby heartbeat by that number.");
pw.println(" monitor-battery [on|off]");
pw.println(" Control monitoring of all battery changes. Off by default. Turning");
pw.println(" on makes get-battery-seq useful.");
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 4988974e95db..1f8cf769ab98 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -240,11 +240,6 @@ public final class JobServiceContext implements ServiceConnection {
}
}
- UsageStatsManagerInternal usageStats =
- LocalServices.getService(UsageStatsManagerInternal.class);
- usageStats.setLastJobRunTime(job.getSourcePackageName(), job.getSourceUserId(),
- mExecutionStartTimeElapsed);
-
// Once we'e begun executing a job, we by definition no longer care whether
// it was inflated from disk with not-yet-coherent delay/deadline bounds.
job.clearPersistedUtcTimes();
@@ -267,12 +262,16 @@ public final class JobServiceContext implements ServiceConnection {
removeOpTimeOutLocked();
return false;
}
+ mJobPackageTracker.noteActive(job);
try {
mBatteryStats.noteJobStart(job.getBatteryName(), job.getSourceUid());
} catch (RemoteException e) {
// Whatever.
}
- mJobPackageTracker.noteActive(job);
+ UsageStatsManagerInternal usageStats =
+ LocalServices.getService(UsageStatsManagerInternal.class);
+ usageStats.setLastJobRunTime(job.getSourcePackageName(), job.getSourceUserId(),
+ mExecutionStartTimeElapsed);
mAvailable = false;
mStoppedReason = null;
mStoppedTime = 0;
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 08ff7bdb0eb8..3867306ee521 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -1346,6 +1346,15 @@ public final class JobStatus {
}
pw.print(prefix); pw.print("Standby bucket: ");
pw.println(bucketName(standbyBucket));
+ if (standbyBucket > 0) {
+ pw.print(prefix); pw.print("Base heartbeat: ");
+ pw.println(baseHeartbeat);
+ }
+ if (whenStandbyDeferred != 0) {
+ pw.print(prefix); pw.print(" Deferred since: ");
+ TimeUtils.formatDuration(whenStandbyDeferred, elapsedRealtimeMillis, pw);
+ pw.println();
+ }
pw.print(prefix); pw.print("Enqueue time: ");
TimeUtils.formatDuration(enqueueTime, elapsedRealtimeMillis, pw);
pw.println();
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 3e43d8ed918d..9d2a8e28a3a0 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -16,6 +16,7 @@
package com.android.server.location;
+import android.annotation.Nullable;
import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.PendingIntent;
@@ -28,11 +29,11 @@ import android.hardware.location.GeofenceHardware;
import android.hardware.location.GeofenceHardwareImpl;
import android.location.Criteria;
import android.location.FusedBatchOptions;
+import android.location.GnssMeasurementsEvent;
+import android.location.GnssNavigationMessage;
import android.location.GnssStatus;
import android.location.IGnssStatusListener;
import android.location.IGnssStatusProvider;
-import android.location.GnssMeasurementsEvent;
-import android.location.GnssNavigationMessage;
import android.location.IGpsGeofenceHardware;
import android.location.ILocationManager;
import android.location.INetInitiatedListener;
@@ -48,16 +49,16 @@ import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.Uri;
import android.os.AsyncTask;
-import android.os.PowerManager.ServiceType;
-import android.os.PowerSaveState;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Bundle;
-import android.os.PersistableBundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.PersistableBundle;
import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
+import android.os.PowerSaveState;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -68,25 +69,21 @@ import android.os.WorkSource.WorkChain;
import android.provider.Settings;
import android.provider.Telephony.Carriers;
import android.provider.Telephony.Sms.Intents;
+import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyManager;
-import android.telephony.CarrierConfigManager;
import android.telephony.gsm.GsmCellLocation;
import android.text.TextUtils;
import android.util.Log;
import android.util.NtpTrustedTime;
-
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
-import com.android.internal.location.gnssmetrics.GnssMetrics;
import com.android.internal.location.GpsNetInitiatedHandler;
import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
-
-import libcore.io.IoUtils;
-
+import com.android.internal.location.gnssmetrics.GnssMetrics;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -97,11 +94,13 @@ import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
-import java.util.Map;
-import java.util.HashMap;
+
+import libcore.io.IoUtils;
/**
* A GNSS implementation of LocationProvider used by LocationManager.
@@ -215,6 +214,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
private static final int INITIALIZE_HANDLER = 13;
private static final int REQUEST_SUPL_CONNECTION = 14;
private static final int RELEASE_SUPL_CONNECTION = 15;
+ private static final int REQUEST_LOCATION = 16;
// Request setid
private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
@@ -248,6 +248,13 @@ public class GnssLocationProvider implements LocationProviderInterface {
private static final int TCP_MIN_PORT = 0;
private static final int TCP_MAX_PORT = 0xffff;
+ // 10 seconds.
+ private static final long LOCATION_TIME_FRESHNESS_THESHOLD_MILLIS = 10 * 1000;
+ // 1 second, or 1 Hz frequency.
+ private static final long LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS = 1000;
+ // 30 seconds.
+ private static final long LOCATION_UPDATE_DURATION_MILLIS = 30 * 1000;
+
/** simpler wrapper for ProviderRequest + Worksource */
private static class GpsRequest {
public ProviderRequest request;
@@ -409,6 +416,8 @@ public class GnssLocationProvider implements LocationProviderInterface {
private final GnssStatusListenerHelper mListenerHelper;
private final GnssMeasurementsProvider mGnssMeasurementsProvider;
private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
+ private final FusedLocationListener mFusedLocationListener = new FusedLocationListener();
+ private static int sNumFusedLocationUpdatesRequests = 0;
// Handler for processing events
private Handler mHandler;
@@ -1074,6 +1083,89 @@ public class GnssLocationProvider implements LocationProviderInterface {
});
}
+ private void handleRequestLocation(boolean independentFromGnss) {
+ if (isRequestLocationRateLimited()) {
+ if (DEBUG) {
+ Log.d(TAG, "RequestLocation is denied due to too frequent requests.");
+ }
+ return;
+ }
+
+ LocationManager locationManager = (LocationManager) mContext.getSystemService(
+ Context.LOCATION_SERVICE);
+
+ if (independentFromGnss) {
+ // For fast GNSS TTFF
+ Location networkLocation = getLastFreshLocation(locationManager,
+ LocationManager.NETWORK_PROVIDER);
+ if (networkLocation != null) {
+ handleUpdateLocation(networkLocation);
+ return;
+ }
+ locationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER,
+ new NetworkLocationListener(),
+ mHandler.getLooper());
+ } else {
+ // For Device-Based Hybrid (E911)
+ locationManager.requestLocationUpdates(LocationManager.FUSED_PROVIDER,
+ LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS, /*minDistance=*/ 0,
+ mFusedLocationListener, mHandler.getLooper());
+ sNumFusedLocationUpdatesRequests++;
+ mHandler.postDelayed(() -> {
+ if (--sNumFusedLocationUpdatesRequests == 0) {
+ locationManager.removeUpdates(mFusedLocationListener);
+ }
+ }, LOCATION_UPDATE_DURATION_MILLIS);
+ }
+ }
+
+ private void injectBestLocation(Location location) {
+ int gnssLocationFlags = LOCATION_HAS_LAT_LONG |
+ (location.hasAltitude() ? LOCATION_HAS_ALTITUDE : 0) |
+ (location.hasSpeed() ? LOCATION_HAS_SPEED : 0) |
+ (location.hasBearing() ? LOCATION_HAS_BEARING : 0) |
+ (location.hasAccuracy() ? LOCATION_HAS_HORIZONTAL_ACCURACY : 0) |
+ (location.hasVerticalAccuracy() ? LOCATION_HAS_VERTICAL_ACCURACY : 0) |
+ (location.hasSpeedAccuracy() ? LOCATION_HAS_SPEED_ACCURACY : 0) |
+ (location.hasBearingAccuracy() ? LOCATION_HAS_BEARING_ACCURACY : 0);
+
+ double latitudeDegrees = location.getLatitude();
+ double longitudeDegrees = location.getLongitude();
+ double altitudeMeters = location.getAltitude();
+ float speedMetersPerSec = location.getSpeed();
+ float bearingDegrees = location.getBearing();
+ float horizontalAccuracyMeters = location.getAccuracy();
+ float verticalAccuracyMeters = location.getVerticalAccuracyMeters();
+ float speedAccuracyMetersPerSecond = location.getSpeedAccuracyMetersPerSecond();
+ float bearingAccuracyDegrees = location.getBearingAccuracyDegrees();
+ long timestamp = location.getTime();
+ native_inject_best_location(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+ altitudeMeters, speedMetersPerSec, bearingDegrees, horizontalAccuracyMeters,
+ verticalAccuracyMeters, speedAccuracyMetersPerSecond, bearingAccuracyDegrees,
+ timestamp);
+ }
+
+ /**
+ * Get the last fresh location.
+ *
+ * Return null if the last location is not available or not fresh.
+ */
+ private @Nullable
+ Location getLastFreshLocation(LocationManager locationManager, String provider) {
+ Location location = locationManager.getLastKnownLocation(provider);
+ if (location != null && System.currentTimeMillis() - location.getTime()
+ < LOCATION_TIME_FRESHNESS_THESHOLD_MILLIS) {
+ return location;
+ }
+ return null;
+ }
+
+ /** Returns true if the location request is too frequent. */
+ private boolean isRequestLocationRateLimited() {
+ // TODO(b/73198123): implement exponential backoff.
+ return false;
+ }
+
private void handleDownloadXtraData() {
if (!mSupportsXtra) {
// native code reports xtra not supported, don't try
@@ -2271,6 +2363,16 @@ public class GnssLocationProvider implements LocationProviderInterface {
}
/**
+ * Called from native code to request location info.
+ */
+ private void requestLocation(boolean independentFromGnss) {
+ if (DEBUG) {
+ Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss);
+ }
+ sendMessage(REQUEST_LOCATION, 0, independentFromGnss);
+ }
+
+ /**
* Called from native code to request utc time info
*/
private void requestUtcTime() {
@@ -2281,7 +2383,6 @@ public class GnssLocationProvider implements LocationProviderInterface {
/**
* Called from native code to request reference location info
*/
-
private void requestRefLocation() {
TelephonyManager phone = (TelephonyManager)
mContext.getSystemService(Context.TELEPHONY_SERVICE);
@@ -2357,6 +2458,9 @@ public class GnssLocationProvider implements LocationProviderInterface {
case INJECT_NTP_TIME:
handleInjectNtpTime();
break;
+ case REQUEST_LOCATION:
+ handleRequestLocation((boolean) msg.obj);
+ break;
case DOWNLOAD_XTRA_DATA:
handleDownloadXtraData();
break;
@@ -2482,15 +2586,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
}
}
- private final class NetworkLocationListener implements LocationListener {
- @Override
- public void onLocationChanged(Location location) {
- // this callback happens on mHandler looper
- if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
- handleUpdateLocation(location);
- }
- }
-
+ private abstract class LocationChangeListener implements LocationListener {
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@@ -2504,6 +2600,26 @@ public class GnssLocationProvider implements LocationProviderInterface {
}
}
+ private final class NetworkLocationListener extends LocationChangeListener {
+ @Override
+ public void onLocationChanged(Location location) {
+ // this callback happens on mHandler looper
+ if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
+ handleUpdateLocation(location);
+ }
+ }
+ }
+
+ private final class FusedLocationListener extends LocationChangeListener {
+ @Override
+ public void onLocationChanged(Location location) {
+ if (LocationManager.FUSED_PROVIDER.equals(location.getProvider())) {
+ Log.d(TAG, "fused location listener: " + location);
+ injectBestLocation(location);
+ }
+ }
+ }
+
private String getSelectedApn() {
Uri uri = Uri.parse("content://telephony/carriers/preferapn");
Cursor cursor = null;
@@ -2668,6 +2784,8 @@ public class GnssLocationProvider implements LocationProviderInterface {
return "RELEASE_SUPL_CONNECTION";
case INJECT_NTP_TIME:
return "INJECT_NTP_TIME";
+ case REQUEST_LOCATION:
+ return "REQUEST_LOCATION";
case DOWNLOAD_XTRA_DATA:
return "DOWNLOAD_XTRA_DATA";
case INJECT_NTP_TIME_FINISHED:
@@ -2788,6 +2906,19 @@ public class GnssLocationProvider implements LocationProviderInterface {
private native int native_read_nmea(byte[] buffer, int bufferSize);
+ private native void native_inject_best_location(
+ int gnssLocationFlags,
+ double latitudeDegrees,
+ double longitudeDegrees,
+ double altitudeMeters,
+ float speedMetersPerSec,
+ float bearingDegrees,
+ float horizontalAccuracyMeters,
+ float verticalAccuracyMeters,
+ float speedAccuracyMetersPerSecond,
+ float bearingAccuracyDegrees,
+ long timestamp);
+
private native void native_inject_location(double latitude, double longitude, float accuracy);
// XTRA Support
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
index c9c93293e2ee..c4f1f3d7369d 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
@@ -19,9 +19,6 @@ package com.android.server.locksettings;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
-
import android.app.AlarmManager;
import android.app.AlarmManager.OnAlarmListener;
import android.app.admin.DevicePolicyManager;
@@ -29,10 +26,9 @@ import android.app.trust.IStrongAuthTracker;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
-import android.os.Binder;
-import android.os.DeadObjectException;
import android.os.Handler;
import android.os.Message;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -40,7 +36,7 @@ import android.util.ArrayMap;
import android.util.Slog;
import android.util.SparseIntArray;
-import java.util.ArrayList;
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
/**
* Keeps track of requests for strong authentication.
@@ -58,7 +54,7 @@ public class LockSettingsStrongAuth {
private static final String STRONG_AUTH_TIMEOUT_ALARM_TAG =
"LockSettingsStrongAuth.timeoutForUser";
- private final ArrayList<IStrongAuthTracker> mStrongAuthTrackers = new ArrayList<>();
+ private final RemoteCallbackList<IStrongAuthTracker> mTrackers = new RemoteCallbackList<>();
private final SparseIntArray mStrongAuthForUser = new SparseIntArray();
private final ArrayMap<Integer, StrongAuthTimeoutAlarmListener>
mStrongAuthTimeoutAlarmListenerForUser = new ArrayMap<>();
@@ -82,12 +78,7 @@ public class LockSettingsStrongAuth {
}
private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) {
- for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
- if (mStrongAuthTrackers.get(i).asBinder() == tracker.asBinder()) {
- return;
- }
- }
- mStrongAuthTrackers.add(tracker);
+ mTrackers.register(tracker);
for (int i = 0; i < mStrongAuthForUser.size(); i++) {
int key = mStrongAuthForUser.keyAt(i);
@@ -101,12 +92,7 @@ public class LockSettingsStrongAuth {
}
private void handleRemoveStrongAuthTracker(IStrongAuthTracker tracker) {
- for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
- if (mStrongAuthTrackers.get(i).asBinder() == tracker.asBinder()) {
- mStrongAuthTrackers.remove(i);
- return;
- }
- }
+ mTrackers.unregister(tracker);
}
private void handleRequireStrongAuth(int strongAuthReason, int userId) {
@@ -157,16 +143,19 @@ public class LockSettingsStrongAuth {
}
private void notifyStrongAuthTrackers(int strongAuthReason, int userId) {
- for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
- try {
- mStrongAuthTrackers.get(i).onStrongAuthRequiredChanged(strongAuthReason, userId);
- } catch (DeadObjectException e) {
- Slog.d(TAG, "Removing dead StrongAuthTracker.");
- mStrongAuthTrackers.remove(i);
+ int i = mTrackers.beginBroadcast();
+ try {
+ while (i > 0) {
i--;
- } catch (RemoteException e) {
- Slog.e(TAG, "Exception while notifying StrongAuthTracker.", e);
+ try {
+ mTrackers.getBroadcastItem(i).onStrongAuthRequiredChanged(
+ strongAuthReason, userId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception while notifying StrongAuthTracker.", e);
+ }
}
+ } finally {
+ mTrackers.finishBroadcast();
}
}
@@ -243,4 +232,5 @@ public class LockSettingsStrongAuth {
}
}
};
+
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS b/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS
new file mode 100644
index 000000000000..bb487fb52c9f
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS
@@ -0,0 +1,4 @@
+aseemk@google.com
+bozhu@google.com
+dementyev@google.com
+robertberry@google.com
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 9f822688a8c0..23a66baf4445 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -170,11 +170,13 @@ public class RecoverableKeyStoreManager {
certXml = CertXml.parse(recoveryServiceCertFile);
} catch (CertParsingException e) {
// TODO: Do not use raw key bytes anymore once the other components are updated
- Log.d(TAG, "Failed to parse the cert file", e);
+ Log.d(TAG, "Failed to parse the input as a cert file: " + HexDump.toHexString(
+ recoveryServiceCertFile));
PublicKey publicKey = parseEcPublicKey(recoveryServiceCertFile);
if (mDatabase.setRecoveryServicePublicKey(userId, uid, publicKey) > 0) {
mDatabase.setShouldCreateSnapshot(userId, uid, true);
}
+ Log.d(TAG, "Successfully set the input as the raw public key");
return;
}
@@ -655,7 +657,7 @@ public class RecoverableKeyStoreManager {
// Ignore the exception to continue to recover the other application keys.
}
}
- if (keyMaterialByAlias.isEmpty()) {
+ if (!applicationKeys.isEmpty() && keyMaterialByAlias.isEmpty()) {
Log.e(TAG, "Failed to recover any of the application keys.");
throw new ServiceSpecificException(ERROR_DECRYPTION_FAILED,
"Failed to recover any of the application keys.");
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index b8771849ac71..21d86c452a8e 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -29,6 +29,7 @@ import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
@@ -76,6 +77,7 @@ import android.util.SparseIntArray;
import android.view.KeyEvent;
import android.view.ViewConfiguration;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
import com.android.server.SystemService;
import com.android.server.Watchdog;
@@ -180,9 +182,8 @@ public class MediaSessionService extends SystemService implements Monitor {
updateUser();
+ registerPackageBroadcastReceivers();
// TODO(jaewan): Query per users
- // TODO(jaewan): Add listener to know changes in list of services.
- // Refer TvInputManagerService.registerBroadcastReceivers()
buildMediaSessionService2List();
}
@@ -437,12 +438,74 @@ public class MediaSessionService extends SystemService implements Monitor {
mHandler.postSessionsChanged(session.getUserId());
}
+ private void registerPackageBroadcastReceivers() {
+ // TODO(jaewan): Only consider changed packages when building session service list
+ // when we make this multi-user aware. At that time,
+ // use PackageMonitor.getChangingUserId() to know which user has changed.
+ IntentFilter filter = new IntentFilter();
+ filter.addDataScheme("package");
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
+ filter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
+ filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+
+ getContext().registerReceiverAsUser(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final int changeUserId = intent.getIntExtra(
+ Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ if (changeUserId == UserHandle.USER_NULL) {
+ Log.w(TAG, "Intent broadcast does not contain user handle: "+ intent);
+ return;
+ }
+ // Check if the package is replacing (i.e. reinstalling)
+ final boolean isReplacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+ // TODO(jaewan): Add multi-user support with this.
+ // final int uid = intent.getIntExtra(Intent.EXTRA_UID, 0);
+
+ if (DEBUG) {
+ Log.d(TAG, "Received change in packages, intent=" + intent);
+ }
+ switch (intent.getAction()) {
+ case Intent.ACTION_PACKAGE_ADDED:
+ case Intent.ACTION_PACKAGE_REMOVED:
+ case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
+ case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
+ if (isReplacing) {
+ // Ignore if the package(s) are replacing. In that case, followings will
+ // happen in order.
+ // 1. ACTION_PACKAGE_REMOVED with isReplacing=true
+ // 2. ACTION_PACKAGE_ADDED with isReplacing=true
+ // 3. ACTION_PACKAGE_REPLACED
+ // (Note that ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE and
+ // ACTION_EXTERNAL_APPLICATIONS_AVAILABLE will be also called with
+ // isReplacing=true for both ASEC hosted packages and packages in
+ // external storage)
+ // Since we only want to update session service list once, ignore
+ // actions above when replacing.
+ // Replacing will be handled only once with the ACTION_PACKAGE_REPLACED.
+ break;
+ }
+ // pass-through
+ case Intent.ACTION_PACKAGE_CHANGED:
+ case Intent.ACTION_PACKAGES_SUSPENDED:
+ case Intent.ACTION_PACKAGES_UNSUSPENDED:
+ case Intent.ACTION_PACKAGE_REPLACED:
+ buildMediaSessionService2List();
+ }
+ }
+ }, UserHandle.ALL, filter, null, BackgroundThread.getHandler());
+ }
+
private void buildMediaSessionService2List() {
if (DEBUG) {
Log.d(TAG, "buildMediaSessionService2List");
}
-
- // TODO(jaewan): Query per users.
+ // TODO(jaewan): Also query for managed profile users.
// TODO(jaewan): Similar codes are also at the updatable. Can't we share codes?
PackageManager manager = getContext().getPackageManager();
List<ResolveInfo> services = new ArrayList<>();
@@ -458,9 +521,13 @@ public class MediaSessionService extends SystemService implements Monitor {
services.addAll(sessionServices);
}
synchronized (mLock) {
- mSessions.clear();
- if (services == null) {
- return;
+ // List to keep the session services that need be removed because they don't exist
+ // in the 'services' above.
+ List<MediaSession2Record> removeCandidates = new ArrayList<>();
+ for (int i = 0; i < mSessions.size(); i++) {
+ if (mSessions.get(i).getToken().getType() != TYPE_SESSION) {
+ removeCandidates.add(mSessions.get(i));
+ }
}
for (int i = 0; i < services.size(); i++) {
if (services.get(i) == null || services.get(i).serviceInfo == null) {
@@ -475,17 +542,35 @@ public class MediaSessionService extends SystemService implements Monitor {
} catch (NameNotFoundException e) {
continue;
}
-
+ SessionToken2 token;
try {
- SessionToken2 token = new SessionToken2(getContext(),
+ token = new SessionToken2(getContext(),
serviceInfo.packageName, serviceInfo.name, uid);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Invalid session service", e);
+ continue;
+ }
+ boolean found = false;
+ for (int j = 0; j < mSessions.size(); j++) {
+ if (token.equals(mSessions.get(j).getToken())) {
+ // If the token already exists, keep it in the mSessions.
+ removeCandidates.remove(mSessions.get(j));
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ // New session service is found.
MediaSession2Record record = new MediaSession2Record(getContext(),
token, mSessionDestroyedListener);
mSessions.add(record);
- } catch (IllegalArgumentException e) {
- Log.d(TAG, "Invalid session service", e);
}
}
+ for (int i = 0; i < removeCandidates.size(); i++) {
+ removeCandidates.get(i).onSessionDestroyed();
+ mSessions.remove(removeCandidates.get(i));
+ }
+ removeCandidates.clear();
}
if (DEBUG) {
Log.d(TAG, "Found " + mSessions.size() + " session services");
@@ -1503,12 +1588,14 @@ public class MediaSessionService extends SystemService implements Monitor {
return tokens;
}
+ // TODO(jaewan): Protect this API with permission
@Override
public void addSessionTokensListener(ISessionTokensListener listener, int userId,
String packageName) {
// TODO(jaewan): Implement.
}
+ // TODO(jaewan): Protect this API with permission
@Override
public void removeSessionTokensListener(ISessionTokensListener listener) {
// TODO(jaewan): Implement
diff --git a/services/core/java/com/android/server/media/OWNERS b/services/core/java/com/android/server/media/OWNERS
new file mode 100644
index 000000000000..6f8d82306e62
--- /dev/null
+++ b/services/core/java/com/android/server/media/OWNERS
@@ -0,0 +1,2 @@
+lajos@google.com
+elaurent@google.com
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index f34662909a85..bd9ec55abc04 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -145,7 +145,9 @@ import android.net.TrafficStats;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Binder;
+import android.os.Build;
import android.os.Environment;
+import android.os.BestClock;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IDeviceIdleController;
@@ -163,6 +165,7 @@ import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ShellCallback;
+import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
@@ -182,7 +185,6 @@ import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.DataUnit;
import android.util.Log;
-import android.util.NtpTrustedTime;
import android.util.Pair;
import android.util.RecurrenceRule;
import android.util.Slog;
@@ -190,7 +192,6 @@ import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.SparseLongArray;
-import android.util.TrustedTime;
import android.util.Xml;
import com.android.internal.R;
@@ -225,7 +226,9 @@ import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
+import java.time.Clock;
import java.time.ZoneId;
+import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Calendar;
@@ -334,8 +337,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final String ACTION_SNOOZE_RAPID =
"com.android.server.net.action.SNOOZE_RAPID";
- private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
-
/**
* Indicates the maximum wait time for admin data to be available;
*/
@@ -361,7 +362,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private final INetworkStatsService mNetworkStats;
private final INetworkManagementService mNetworkManager;
private UsageStatsManagerInternal mUsageStats;
- private final TrustedTime mTime;
+ private final Clock mClock;
private final UserManager mUserManager;
private final CarrierConfigManager mCarrierConfigManager;
@@ -517,24 +518,29 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
INetworkStatsService networkStats, INetworkManagementService networkManagement) {
this(context, activityManager, networkStats, networkManagement,
- AppGlobals.getPackageManager(), NtpTrustedTime.getInstance(context), getSystemDir(),
+ AppGlobals.getPackageManager(), getDefaultClock(), getDefaultSystemDir(),
false);
}
- private static File getSystemDir() {
+ private static @NonNull File getDefaultSystemDir() {
return new File(Environment.getDataDirectory(), "system");
}
+ private static @NonNull Clock getDefaultClock() {
+ return new BestClock(ZoneOffset.UTC, SystemClock.currentNetworkTimeClock(),
+ Clock.systemUTC());
+ }
+
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
INetworkStatsService networkStats, INetworkManagementService networkManagement,
- IPackageManager pm, TrustedTime time, File systemDir, boolean suppressDefaultPolicy) {
+ IPackageManager pm, Clock clock, File systemDir, boolean suppressDefaultPolicy) {
mContext = checkNotNull(context, "missing context");
mActivityManager = checkNotNull(activityManager, "missing activityManager");
mNetworkStats = checkNotNull(networkStats, "missing networkStats");
mNetworkManager = checkNotNull(networkManagement, "missing networkManagement");
mDeviceIdleController = IDeviceIdleController.Stub.asInterface(ServiceManager.getService(
Context.DEVICE_IDLE_CONTROLLER));
- mTime = checkNotNull(time, "missing TrustedTime");
+ mClock = checkNotNull(clock, "missing Clock");
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
mIPm = pm;
@@ -931,7 +937,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// on background handler thread, and verified
// READ_NETWORK_USAGE_HISTORY permission above.
- maybeRefreshTrustedTime();
synchronized (mNetworkPoliciesSecondLock) {
updateNetworkEnabledNL();
updateNotificationsNL();
@@ -1041,7 +1046,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// cycle boundary to recompute notifications.
// examine stats for each active policy
- final long now = currentTimeMillis();
+ final long now = mClock.millis();
for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
// ignore policies that aren't relevant to user
@@ -1298,7 +1303,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// on background handler thread, and verified CONNECTIVITY_INTERNAL
// permission above.
- maybeRefreshTrustedTime();
synchronized (mUidRulesFirstLock) {
synchronized (mNetworkPoliciesSecondLock) {
ensureActiveMobilePolicyAL();
@@ -1461,7 +1465,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final TelephonyManager tele = mContext.getSystemService(TelephonyManager.class);
final String subscriberId = tele.getSubscriberId(subId);
- maybeRefreshTrustedTime();
synchronized (mUidRulesFirstLock) {
synchronized (mNetworkPoliciesSecondLock) {
final boolean added = ensureActiveMobilePolicyAL(subId, subscriberId);
@@ -1722,7 +1725,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final long totalBytes = getTotalBytes(
NetworkTemplate.buildTemplateMobileAll(state.subscriberId), start, end);
final long remainingBytes = limitBytes - totalBytes;
- final long remainingDays = Math.max(1, (end - currentTimeMillis())
+ final long remainingDays = Math.max(1, (end - mClock.millis())
/ TimeUnit.DAYS.toMillis(1));
if (remainingBytes > 0) {
quotaBytes = (remainingBytes / remainingDays) / 10;
@@ -2443,7 +2446,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final long token = Binder.clearCallingIdentity();
try {
- maybeRefreshTrustedTime();
synchronized (mUidRulesFirstLock) {
synchronized (mNetworkPoliciesSecondLock) {
normalizePoliciesNL(policies);
@@ -2523,8 +2525,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
void performSnooze(NetworkTemplate template, int type) {
- maybeRefreshTrustedTime();
- final long currentTime = currentTimeMillis();
+ final long currentTime = mClock.millis();
synchronized (mUidRulesFirstLock) {
synchronized (mNetworkPoliciesSecondLock) {
// find and snooze local policy that matches
@@ -2570,7 +2571,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
final long token = Binder.clearCallingIdentity();
try {
- maybeRefreshTrustedTime();
synchronized (mUidRulesFirstLock) {
setRestrictBackgroundUL(restrictBackground);
}
@@ -2759,6 +2759,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
return;
}
+ // Fourth check: is caller a testing app on a debug build?
+ final boolean enableDebug = Build.IS_USERDEBUG || Build.IS_ENG;
+ if (enableDebug && callingPackage
+ .equals(SystemProperties.get("fw.sub_plan_owner." + subId, null))) {
+ return;
+ }
+
// Final check: does the caller hold a permission?
mContext.enforceCallingOrSelfPermission(MANAGE_SUBSCRIPTION_PLANS, TAG);
}
@@ -2908,7 +2915,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final long token = Binder.clearCallingIdentity();
try {
- maybeRefreshTrustedTime();
synchronized (mUidRulesFirstLock) {
synchronized (mNetworkPoliciesSecondLock) {
mSubscriptionPlans.put(subId, plans);
@@ -4020,7 +4026,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
case MSG_LIMIT_REACHED: {
final String iface = (String) msg.obj;
- maybeRefreshTrustedTime();
synchronized (mNetworkPoliciesSecondLock) {
if (mMeteredIfaces.contains(iface)) {
try {
@@ -4385,19 +4390,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
- /**
- * Try refreshing {@link #mTime} when stale.
- */
- void maybeRefreshTrustedTime() {
- if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) {
- mTime.forceRefresh();
- }
- }
-
- private long currentTimeMillis() {
- return mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis();
- }
-
private static Intent buildAllowBackgroundDataIntent() {
return new Intent(ACTION_ALLOW_BACKGROUND);
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 76c4db134036..d1aa21276bb0 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -68,6 +68,7 @@ import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet;
+import android.annotation.NonNull;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.usage.NetworkStatsManager;
@@ -97,6 +98,7 @@ import android.net.TrafficStats;
import android.os.Binder;
import android.os.DropBoxManager;
import android.os.Environment;
+import android.os.BestClock;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -120,10 +122,8 @@ import android.util.ArraySet;
import android.util.EventLog;
import android.util.Log;
import android.util.MathUtils;
-import android.util.NtpTrustedTime;
import android.util.Slog;
import android.util.SparseIntArray;
-import android.util.TrustedTime;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
@@ -140,6 +140,8 @@ import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
+import java.time.Clock;
+import java.time.ZoneOffset;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -167,7 +169,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private final Context mContext;
private final INetworkManagementService mNetworkManager;
private final AlarmManager mAlarmManager;
- private final TrustedTime mTime;
+ private final Clock mClock;
private final TelephonyManager mTeleManager;
private final NetworkStatsSettings mSettings;
private final NetworkStatsObservers mStatsObservers;
@@ -202,7 +204,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
*/
public interface NetworkStatsSettings {
public long getPollInterval();
- public long getTimeCacheMaxAge();
public boolean getSampleEnabled();
public boolean getAugmentEnabled();
@@ -281,16 +282,21 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private long mPersistThreshold = 2 * MB_IN_BYTES;
private long mGlobalAlertBytes;
- private static File getDefaultSystemDir() {
+ private static @NonNull File getDefaultSystemDir() {
return new File(Environment.getDataDirectory(), "system");
}
- private static File getDefaultBaseDir() {
+ private static @NonNull File getDefaultBaseDir() {
File baseDir = new File(getDefaultSystemDir(), "netstats");
baseDir.mkdirs();
return baseDir;
}
+ private static @NonNull Clock getDefaultClock() {
+ return new BestClock(ZoneOffset.UTC, SystemClock.currentNetworkTimeClock(),
+ Clock.systemUTC());
+ }
+
public static NetworkStatsService create(Context context,
INetworkManagementService networkManager) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
@@ -299,7 +305,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
NetworkStatsService service = new NetworkStatsService(context, networkManager, alarmManager,
- wakeLock, NtpTrustedTime.getInstance(context), TelephonyManager.getDefault(),
+ wakeLock, getDefaultClock(), TelephonyManager.getDefault(),
new DefaultNetworkStatsSettings(context), new NetworkStatsObservers(),
getDefaultSystemDir(), getDefaultBaseDir());
@@ -313,13 +319,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@VisibleForTesting
NetworkStatsService(Context context, INetworkManagementService networkManager,
- AlarmManager alarmManager, PowerManager.WakeLock wakeLock, TrustedTime time,
+ AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock,
TelephonyManager teleManager, NetworkStatsSettings settings,
NetworkStatsObservers statsObservers, File systemDir, File baseDir) {
mContext = checkNotNull(context, "missing Context");
mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService");
mAlarmManager = checkNotNull(alarmManager, "missing AlarmManager");
- mTime = checkNotNull(time, "missing TrustedTime");
+ mClock = checkNotNull(clock, "missing Clock");
mSettings = checkNotNull(settings, "missing NetworkStatsSettings");
mTeleManager = checkNotNull(teleManager, "missing TelephonyManager");
mWakeLock = checkNotNull(wakeLock, "missing WakeLock");
@@ -413,8 +419,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
mContext.unregisterReceiver(mUserReceiver);
mContext.unregisterReceiver(mShutdownReceiver);
- final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
- : System.currentTimeMillis();
+ final long currentTime = mClock.millis();
// persist any pending stats
mDevRecorder.forcePersistLocked(currentTime);
@@ -831,8 +836,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
// update and persist if beyond new thresholds
- final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
- : System.currentTimeMillis();
+ final long currentTime = mClock.millis();
synchronized (mStatsLock) {
if (!mSystemReady) return;
@@ -1170,8 +1174,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
*/
@GuardedBy("mStatsLock")
private void bootstrapStatsLocked() {
- final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
- : System.currentTimeMillis();
+ final long currentTime = mClock.millis();
try {
recordSnapshotLocked(currentTime);
@@ -1183,11 +1186,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
private void performPoll(int flags) {
- // try refreshing time source when stale
- if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) {
- mTime.forceRefresh();
- }
-
synchronized (mStatsLock) {
mWakeLock.acquire();
@@ -1215,8 +1213,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0;
// TODO: consider marking "untrusted" times in historical stats
- final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
- : System.currentTimeMillis();
+ final long currentTime = mClock.millis();
try {
recordSnapshotLocked(currentTime);
@@ -1268,7 +1265,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@GuardedBy("mStatsLock")
private void performSampleLocked() {
// TODO: migrate trustedtime fixes to separate binary log events
- final long trustedTime = mTime.hasCache() ? mTime.currentTimeMillis() : -1;
+ final long currentTime = mClock.millis();
NetworkTemplate template;
NetworkStats.Entry devTotal;
@@ -1285,7 +1282,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets,
xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
- trustedTime);
+ currentTime);
// collect wifi sample
template = buildTemplateWifiWildcard();
@@ -1297,7 +1294,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets,
xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
- trustedTime);
+ currentTime);
}
/**
@@ -1621,10 +1618,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
return getGlobalLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS);
}
@Override
- public long getTimeCacheMaxAge() {
- return getGlobalLong(NETSTATS_TIME_CACHE_MAX_AGE, DAY_IN_MILLIS);
- }
- @Override
public long getGlobalAlertBytes(long def) {
return getGlobalLong(NETSTATS_GLOBAL_ALERT_BYTES, def);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 3800017f0a08..548f15419798 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1836,6 +1836,10 @@ public class NotificationManagerService extends SystemService {
if (index >= 0) {
record = mToastQueue.get(index);
record.update(duration);
+ try {
+ record.callback.hide();
+ } catch (RemoteException e) {
+ }
record.update(callback);
} else {
Binder token = new Binder();
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 7e3b5516b8cc..0a870978d160 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -18,8 +18,10 @@ package com.android.server.notification;
import android.app.AppOpsManager;
import android.app.AutomaticZenRule;
+import android.app.Notification;
import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
+import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -44,6 +46,7 @@ import android.os.Message;
import android.os.Process;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.provider.Settings;
import android.provider.Settings.Global;
import android.service.notification.Condition;
import android.service.notification.ConditionProviderService;
@@ -61,6 +64,8 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.server.LocalServices;
import libcore.io.IoUtils;
@@ -89,6 +94,7 @@ public class ZenModeHelper {
private final H mHandler;
private final SettingsObserver mSettingsObserver;
@VisibleForTesting protected final AppOpsManager mAppOps;
+ @VisibleForTesting protected final NotificationManager mNotificationManager;
protected ZenModeConfig mDefaultConfig;
private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
private final ZenModeFiltering mFiltering;
@@ -112,12 +118,14 @@ public class ZenModeHelper {
protected String mDefaultRuleEveryNightName;
protected String mDefaultRuleEventsName;
+ @VisibleForTesting protected boolean mIsBootComplete;
public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
mContext = context;
mHandler = new H(looper);
addCallback(mMetrics);
mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ mNotificationManager = context.getSystemService(NotificationManager.class);
mDefaultConfig = new ZenModeConfig();
setDefaultZenRules(mContext);
@@ -197,6 +205,8 @@ public class ZenModeHelper {
mHandler.postMetricsTimer();
cleanUpZenRules();
evaluateZenMode("onSystemReady", true);
+ mIsBootComplete = true;
+ showZenUpgradeNotification(mZenMode);
}
public void onUserSwitched(int user) {
@@ -612,6 +622,10 @@ public class ZenModeHelper {
throws XmlPullParserException, IOException {
final ZenModeConfig config = ZenModeConfig.readXml(parser);
if (config != null) {
+ if (config.version < ZenModeConfig.XML_VERSION) {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 1);
+ }
if (forRestore) {
//TODO: http://b/22388012
if (config.user != UserHandle.USER_SYSTEM) {
@@ -755,8 +769,10 @@ public class ZenModeHelper {
return Global.getInt(mContext.getContentResolver(), Global.ZEN_MODE, Global.ZEN_MODE_OFF);
}
- private void setZenModeSetting(int zen) {
+ @VisibleForTesting
+ protected void setZenModeSetting(int zen) {
Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zen);
+ showZenUpgradeNotification(zen);
}
private int getPreviousRingerModeSetting() {
@@ -1139,6 +1155,41 @@ public class ZenModeHelper {
}
}
+ private void showZenUpgradeNotification(int zen) {
+ final boolean showNotification = mIsBootComplete
+ && zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ && Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 0) != 0;
+
+ if (showNotification) {
+ mNotificationManager.notify(TAG, SystemMessage.NOTE_ZEN_UPGRADE,
+ createZenUpgradeNotification());
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
+ }
+ }
+
+ @VisibleForTesting
+ protected Notification createZenUpgradeNotification() {
+ Intent intent = new Intent(Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS)
+ .setPackage("com.android.settings")
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ final Bundle extras = new Bundle();
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
+ mContext.getResources().getString(R.string.global_action_settings));
+ return new Notification.Builder(mContext, SystemNotificationChannels.SYSTEM_CHANGES)
+ .setSmallIcon(R.drawable.ic_settings_24dp)
+ .setContentTitle(mContext.getResources().getString(
+ R.string.zen_upgrade_notification_title))
+ .setContentText(mContext.getResources().getString(
+ R.string.zen_upgrade_notification_content))
+ .setAutoCancel(true)
+ .setLocalOnly(true)
+ .addExtras(extras)
+ .setContentIntent(PendingIntent.getActivity(mContext, 0, intent, 0, null))
+ .build();
+ }
+
private final class Metrics extends Callback {
private static final String COUNTER_PREFIX = "dnd_mode_";
private static final long MINIMUM_LOG_PERIOD_MS = 60 * 1000;
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 4bc4a7ecc055..7467954918d8 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -544,7 +544,28 @@ public final class OverlayManagerService extends SystemService {
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- return mImpl.setEnabledExclusive(packageName, userId);
+ return mImpl.setEnabledExclusive(packageName, false /* withinCategory */,
+ userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public boolean setEnabledExclusiveInCategory(@Nullable String packageName, 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.setEnabledExclusive(packageName, true /* withinCategory */,
+ userId);
}
} finally {
Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 6e02db7b25ea..a027fc6f2580 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -35,6 +35,8 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
+import libcore.util.Objects;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Iterator;
@@ -103,12 +105,14 @@ final class OverlayManagerServiceImpl {
for (int i = 0; i < overlayPackagesSize; i++) {
final PackageInfo overlayPackage = overlayPackages.get(i);
final OverlayInfo oi = storedOverlayInfos.get(overlayPackage.packageName);
- if (oi == null || !oi.targetPackageName.equals(overlayPackage.overlayTarget)) {
+ if (oi == null || !oi.targetPackageName.equals(overlayPackage.overlayTarget)
+ || !Objects.equal(oi.category, overlayPackage.overlayCategory)) {
// Update the overlay if it didn't exist or had the wrong target package.
mSettings.init(overlayPackage.packageName, newUserId,
overlayPackage.overlayTarget,
overlayPackage.applicationInfo.getBaseCodePath(),
- overlayPackage.isStaticOverlayPackage(), overlayPackage.overlayPriority);
+ overlayPackage.isStaticOverlayPackage(), overlayPackage.overlayPriority,
+ overlayPackage.overlayCategory);
if (oi == null) {
// This overlay does not exist in our settings.
@@ -259,7 +263,8 @@ final class OverlayManagerServiceImpl {
mSettings.init(packageName, userId, overlayPackage.overlayTarget,
overlayPackage.applicationInfo.getBaseCodePath(),
- overlayPackage.isStaticOverlayPackage(), overlayPackage.overlayPriority);
+ overlayPackage.isStaticOverlayPackage(), overlayPackage.overlayPriority,
+ overlayPackage.overlayCategory);
try {
if (updateState(overlayPackage.overlayTarget, packageName, userId, 0)) {
mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
@@ -320,7 +325,7 @@ final class OverlayManagerServiceImpl {
if (!oldOi.targetPackageName.equals(pkg.overlayTarget)) {
mSettings.init(packageName, userId, pkg.overlayTarget,
pkg.applicationInfo.getBaseCodePath(), pkg.isStaticOverlayPackage(),
- pkg.overlayPriority);
+ pkg.overlayPriority, pkg.overlayCategory);
}
if (updateState(pkg.overlayTarget, packageName, userId, 0)) {
@@ -394,10 +399,11 @@ final class OverlayManagerServiceImpl {
}
}
- boolean setEnabledExclusive(@NonNull final String packageName, final int userId) {
+ boolean setEnabledExclusive(@NonNull final String packageName, boolean withinCategory,
+ final int userId) {
if (DEBUG) {
- Slog.d(TAG, String.format("setEnabledExclusive packageName=%s userId=%d", packageName,
- userId));
+ Slog.d(TAG, String.format("setEnabledExclusive packageName=%s"
+ + " withinCategory=%s userId=%d", packageName, withinCategory, userId));
}
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
@@ -428,6 +434,11 @@ final class OverlayManagerServiceImpl {
// Don't touch static overlays.
continue;
}
+ if (withinCategory && !Objects.equal(disabledOverlayPackageInfo.overlayCategory,
+ oi.category)) {
+ // Don't touch overlays from other categories.
+ continue;
+ }
// Disable the overlay.
modified |= mSettings.setEnabled(disabledOverlayPackageName, userId, false);
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index a80cae4dcb4b..e57fa0b51d39 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -20,10 +20,7 @@ import static com.android.server.om.OverlayManagerService.DEBUG;
import static com.android.server.om.OverlayManagerService.TAG;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.om.OverlayInfo;
-import android.os.UserHandle;
-import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
import android.util.Slog;
import android.util.Xml;
@@ -67,11 +64,11 @@ final class OverlayManagerSettings {
void init(@NonNull final String packageName, final int userId,
@NonNull final String targetPackageName, @NonNull final String baseCodePath,
- boolean isStatic, int priority) {
+ boolean isStatic, int priority, String overlayCategory) {
remove(packageName, userId);
final SettingsItem item =
new SettingsItem(packageName, userId, targetPackageName, baseCodePath,
- isStatic, priority);
+ isStatic, priority, overlayCategory);
if (isStatic) {
int i;
for (i = mItems.size() - 1; i >= 0; i--) {
@@ -292,6 +289,7 @@ final class OverlayManagerSettings {
pw.print("mState.............: "); pw.println(OverlayInfo.stateToString(item.getState()));
pw.print("mIsEnabled.........: "); pw.println(item.isEnabled());
pw.print("mIsStatic..........: "); pw.println(item.isStatic());
+ pw.print("mCategory..........: "); pw.println(item.mCategory);
pw.decreaseIndent();
pw.println("}");
@@ -317,6 +315,7 @@ final class OverlayManagerSettings {
private static final String ATTR_TARGET_PACKAGE_NAME = "targetPackageName";
private static final String ATTR_IS_STATIC = "isStatic";
private static final String ATTR_PRIORITY = "priority";
+ private static final String ATTR_CATEGORY = "category";
private static final String ATTR_USER_ID = "userId";
private static final String ATTR_VERSION = "version";
@@ -371,9 +370,10 @@ final class OverlayManagerSettings {
final boolean isEnabled = XmlUtils.readBooleanAttribute(parser, ATTR_IS_ENABLED);
final boolean isStatic = XmlUtils.readBooleanAttribute(parser, ATTR_IS_STATIC);
final int priority = XmlUtils.readIntAttribute(parser, ATTR_PRIORITY);
+ final String category = XmlUtils.readStringAttribute(parser, ATTR_CATEGORY);
- return new SettingsItem(packageName, userId, targetPackageName, baseCodePath, state,
- isEnabled, isStatic, priority);
+ return new SettingsItem(packageName, userId, targetPackageName, baseCodePath,
+ state, isEnabled, isStatic, priority, category);
}
public static void persist(@NonNull final ArrayList<SettingsItem> table,
@@ -405,6 +405,7 @@ final class OverlayManagerSettings {
XmlUtils.writeBooleanAttribute(xml, ATTR_IS_ENABLED, item.mIsEnabled);
XmlUtils.writeBooleanAttribute(xml, ATTR_IS_STATIC, item.mIsStatic);
XmlUtils.writeIntAttribute(xml, ATTR_PRIORITY, item.mPriority);
+ XmlUtils.writeStringAttribute(xml, ATTR_CATEGORY, item.mCategory);
xml.endTag(null, TAG_ITEM);
}
}
@@ -419,17 +420,19 @@ final class OverlayManagerSettings {
private OverlayInfo mCache;
private boolean mIsStatic;
private int mPriority;
+ private final String mCategory;
SettingsItem(@NonNull final String packageName, final int userId,
@NonNull final String targetPackageName, @NonNull final String baseCodePath,
final @OverlayInfo.State int state, final boolean isEnabled, final boolean isStatic,
- final int priority) {
+ final int priority, String category) {
mPackageName = packageName;
mUserId = userId;
mTargetPackageName = targetPackageName;
mBaseCodePath = baseCodePath;
mState = state;
mIsEnabled = isEnabled;
+ mCategory = category;
mCache = null;
mIsStatic = isStatic;
mPriority = priority;
@@ -437,9 +440,9 @@ final class OverlayManagerSettings {
SettingsItem(@NonNull final String packageName, final int userId,
@NonNull final String targetPackageName, @NonNull final String baseCodePath,
- final boolean isStatic, final int priority) {
+ final boolean isStatic, final int priority, String category) {
this(packageName, userId, targetPackageName, baseCodePath, OverlayInfo.STATE_UNKNOWN,
- false, isStatic, priority);
+ false, isStatic, priority, category);
}
private String getTargetPackageName() {
@@ -491,8 +494,8 @@ final class OverlayManagerSettings {
private OverlayInfo getOverlayInfo() {
if (mCache == null) {
- mCache = new OverlayInfo(mPackageName, mTargetPackageName, mBaseCodePath, mState,
- mUserId);
+ mCache = new OverlayInfo(mPackageName, mTargetPackageName, mCategory, mBaseCodePath,
+ mState, mUserId);
}
return mCache;
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
index 29ddaf49e200..54bb115c5405 100644
--- a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
+++ b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
@@ -56,6 +56,8 @@ final class OverlayManagerShellCommand extends ShellCommand {
return runEnableDisable(true);
case "disable":
return runEnableDisable(false);
+ case "enable-exclusive":
+ return runEnableExclusive();
case "set-priority":
return runSetPriority();
default:
@@ -86,6 +88,10 @@ final class OverlayManagerShellCommand extends ShellCommand {
out.println(" Enable overlay package PACKAGE.");
out.println(" disable [--user USER_ID] PACKAGE");
out.println(" Disable overlay package PACKAGE.");
+ out.println(" enable-exclusive [--user USER_ID] [--category] PACKAGE");
+ out.println(" Enable overlay package PACKAGE and disable all other overlays for");
+ out.println(" its target package. If the --category option is given, only disables");
+ out.println(" other overlays in the same category.");
out.println(" set-priority [--user USER_ID] PACKAGE PARENT|lowest|highest");
out.println(" Change the priority of the overlay PACKAGE to be just higher than");
out.println(" the priority of PACKAGE_PARENT If PARENT is the special keyword");
@@ -157,6 +163,33 @@ final class OverlayManagerShellCommand extends ShellCommand {
return mInterface.setEnabled(packageName, enable, userId) ? 0 : 1;
}
+ private int runEnableExclusive() throws RemoteException {
+ final PrintWriter err = getErrPrintWriter();
+
+ int userId = UserHandle.USER_SYSTEM;
+ boolean inCategory = false;
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "--user":
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ break;
+ case "--category":
+ inCategory = true;
+ break;
+ default:
+ err.println("Error: Unknown option: " + opt);
+ return 1;
+ }
+ }
+ final String overlay = getNextArgRequired();
+ if (inCategory) {
+ return mInterface.setEnabledExclusiveInCategory(overlay, userId) ? 0 : 1;
+ } else {
+ return mInterface.setEnabledExclusive(overlay, true, userId) ? 0 : 1;
+ }
+ }
+
private int runSetPriority() throws RemoteException {
final PrintWriter err = getErrPrintWriter();
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index b79caca317a4..9bba9ed0f612 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -63,9 +63,8 @@ public class Installer extends SystemService {
public static final int DEXOPT_STORAGE_DE = 1 << 8;
/** Indicates that dexopt is invoked from the background service. */
public static final int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9;
- /* Indicates that dexopt should not restrict access to private APIs.
- * Must be kept in sync with com.android.internal.os.ZygoteInit. */
- public static final int DEXOPT_DISABLE_HIDDEN_API_CHECKS = 1 << 10;
+ /** Indicates that dexopt should restrict access to private APIs. */
+ public static final int DEXOPT_ENABLE_HIDDEN_API_CHECKS = 1 << 10;
// NOTE: keep in sync with installd
public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
@@ -290,14 +289,14 @@ public class Installer extends SystemService {
int dexoptNeeded, @Nullable String outputPath, int dexFlags,
String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries,
@Nullable String seInfo, boolean downgrade, int targetSdkVersion,
- @Nullable String profileName, @Nullable String dexMetadataPath)
- throws InstallerException {
+ @Nullable String profileName, @Nullable String dexMetadataPath,
+ @Nullable String compilationReason) throws InstallerException {
assertValidInstructionSet(instructionSet);
if (!checkBeforeRemote()) return;
try {
mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo, downgrade,
- targetSdkVersion, profileName, dexMetadataPath);
+ targetSdkVersion, profileName, dexMetadataPath, compilationReason);
} catch (Exception e) {
throw InstallerException.from(e);
}
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index fc73142c4858..9420a6c5c15b 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -262,11 +262,12 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
int dexFlags, String compilerFilter, @Nullable String volumeUuid,
@Nullable String sharedLibraries, @Nullable String seInfo, boolean downgrade,
int targetSdkVersion, @Nullable String profileName,
- @Nullable String dexMetadataPath) throws InstallerException {
+ @Nullable String dexMetadataPath, @Nullable String dexoptCompilationReason)
+ throws InstallerException {
final StringBuilder builder = new StringBuilder();
- // The version. Right now it's 6.
- builder.append("6 ");
+ // The version. Right now it's 7.
+ builder.append("7 ");
builder.append("dexopt");
@@ -285,6 +286,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
encodeParameter(builder, targetSdkVersion);
encodeParameter(builder, profileName);
encodeParameter(builder, dexMetadataPath);
+ encodeParameter(builder, dexoptCompilationReason);
commands.add(builder.toString());
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 2c68e67a3bd5..77bf67daa478 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -34,7 +34,6 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.pm.Installer.InstallerException;
-import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.DexoptUtils;
import com.android.server.pm.dex.PackageDexUsage;
@@ -57,13 +56,14 @@ import static com.android.server.pm.Installer.DEXOPT_FORCE;
import static com.android.server.pm.Installer.DEXOPT_STORAGE_CE;
import static com.android.server.pm.Installer.DEXOPT_STORAGE_DE;
import static com.android.server.pm.Installer.DEXOPT_IDLE_BACKGROUND_JOB;
-import static com.android.server.pm.Installer.DEXOPT_DISABLE_HIDDEN_API_CHECKS;
+import static com.android.server.pm.Installer.DEXOPT_ENABLE_HIDDEN_API_CHECKS;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
import static com.android.server.pm.PackageManagerService.WATCHDOG_TIMEOUT;
-import static dalvik.system.DexFile.getNonProfileGuidedCompilerFilter;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.getReasonName;
+
import static dalvik.system.DexFile.getSafeModeCompilerFilter;
import static dalvik.system.DexFile.isProfileGuidedCompilerFilter;
@@ -231,7 +231,8 @@ public class PackageDexOptimizer {
for (String dexCodeIsa : dexCodeInstructionSets) {
int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter,
profileUpdated, classLoaderContexts[i], dexoptFlags, sharedGid,
- packageStats, options.isDowngrade(), profileName, dexMetadataPath);
+ packageStats, options.isDowngrade(), profileName, dexMetadataPath,
+ options.getCompilationReason());
// The end result is:
// - FAILED if any path failed,
// - PERFORMED if at least one path needed compilation,
@@ -256,7 +257,7 @@ public class PackageDexOptimizer {
private int dexOptPath(PackageParser.Package pkg, String path, String isa,
String compilerFilter, boolean profileUpdated, String classLoaderContext,
int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade,
- String profileName, String dexMetadataPath) {
+ String profileName, String dexMetadataPath, int compilationReason) {
int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, classLoaderContext,
profileUpdated, downgrade);
if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) {
@@ -283,7 +284,7 @@ public class PackageDexOptimizer {
mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags,
compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo,
false /* downgrade*/, pkg.applicationInfo.targetSdkVersion,
- profileName, dexMetadataPath);
+ profileName, dexMetadataPath, getReasonName(compilationReason));
if (packageStats != null) {
long endTime = System.currentTimeMillis();
@@ -394,7 +395,7 @@ public class PackageDexOptimizer {
// Note this trades correctness for performance since the resulting slow down is
// unacceptable in some cases until b/64530081 is fixed.
String classLoaderContext = SKIP_SHARED_LIBRARY_CHECK;
-
+ int reason = options.getCompilationReason();
try {
for (String isa : dexUseInfo.getLoaderIsas()) {
// Reuse the same dexopt path as for the primary apks. We don't need all the
@@ -405,7 +406,7 @@ public class PackageDexOptimizer {
/*oatDir*/ null, dexoptFlags,
compilerFilter, info.volumeUuid, classLoaderContext, info.seInfoUser,
options.isDowngrade(), info.targetSdkVersion, /*profileName*/ null,
- /*dexMetadataPath*/ null);
+ /*dexMetadataPath*/ null, getReasonName(reason));
}
return DEX_OPT_PERFORMED;
@@ -528,11 +529,9 @@ public class PackageDexOptimizer {
boolean isPublic = !info.isForwardLocked() &&
(!isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata());
int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
- // System apps are invoked with a runtime flag which exempts them from
- // restrictions on hidden API usage. We dexopt with the same runtime flag
- // otherwise offending methods would have to be re-verified at runtime
- // and we want to avoid the performance overhead of that.
- int hiddenApiFlag = info.isAllowedToUseHiddenApi() ? DEXOPT_DISABLE_HIDDEN_API_CHECKS : 0;
+ // Some apps are executed with restrictions on hidden API usage. If this app is one
+ // of them, pass a flag to dexopt to enable the same restrictions during compilation.
+ int hiddenApiFlag = info.isAllowedToUseHiddenApi() ? 0 : DEXOPT_ENABLE_HIDDEN_API_CHECKS;
int dexFlags =
(isPublic ? DEXOPT_PUBLIC : 0)
| (debuggable ? DEXOPT_DEBUGGABLE : 0)
@@ -655,8 +654,8 @@ public class PackageDexOptimizer {
if ((flags & DEXOPT_IDLE_BACKGROUND_JOB) == DEXOPT_IDLE_BACKGROUND_JOB) {
flagsList.add("idle_background_job");
}
- if ((flags & DEXOPT_DISABLE_HIDDEN_API_CHECKS) == DEXOPT_DISABLE_HIDDEN_API_CHECKS) {
- flagsList.add("disable_hidden_api_checks");
+ if ((flags & DEXOPT_ENABLE_HIDDEN_API_CHECKS) == DEXOPT_ENABLE_HIDDEN_API_CHECKS) {
+ flagsList.add("enable_hidden_api_checks");
}
return String.join(",", flagsList);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3cd24f967a86..f23918e7e85c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -553,9 +553,9 @@ public class PackageManagerService extends IPackageManager.Stub
public static final String PLATFORM_PACKAGE_NAME = "android";
- static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
+ public static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
- static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
+ public static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
DEFAULT_CONTAINER_PACKAGE,
"com.android.defcontainer.DefaultContainerService");
@@ -598,6 +598,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// Compilation reasons.
+ public static final int REASON_UNKNOWN = -1;
public static final int REASON_FIRST_BOOT = 0;
public static final int REASON_BOOT = 1;
public static final int REASON_INSTALL = 2;
@@ -2720,11 +2721,12 @@ public class PackageManagerService extends IPackageManager.Stub
* application can be scanned.
*/
if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
- logCriticalInfo(Log.WARN, "Expecting better updated system app for "
- + ps.name + "; removing system app. Last known codePath="
- + ps.codePathString + ", installStatus=" + ps.installStatus
- + ", versionCode=" + ps.versionCode + "; scanned versionCode="
- + scannedPkg.getLongVersionCode());
+ logCriticalInfo(Log.WARN,
+ "Expecting better updated system app for " + ps.name
+ + "; removing system app. Last known"
+ + " codePath=" + ps.codePathString
+ + ", versionCode=" + ps.versionCode
+ + "; scanned versionCode=" + scannedPkg.getLongVersionCode());
removePackageLI(scannedPkg, true);
mExpectingBetter.put(ps.name, ps.codePath);
}
@@ -2753,18 +2755,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- //look for any incomplete package installations
- ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
- for (int i = 0; i < deletePkgsList.size(); i++) {
- // Actual deletion of code and data will be handled by later
- // reconciliation step
- final String packageName = deletePkgsList.get(i).name;
- logCriticalInfo(Log.WARN, "Cleaning up incompletely installed app: " + packageName);
- synchronized (mPackages) {
- mSettings.removePackageLPw(packageName);
- }
- }
-
//delete tmp files
deleteTempPackageFiles();
@@ -8847,7 +8837,7 @@ public class PackageManagerService extends IPackageManager.Stub
final long startTime = System.nanoTime();
final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */,
- getCompilerFilterForReason(causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT),
+ causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT,
false /* bootComplete */);
final int elapsedTimeSeconds =
@@ -8874,7 +8864,7 @@ public class PackageManagerService extends IPackageManager.Stub
* and {@code numberOfPackagesFailed}.
*/
private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, boolean showDialog,
- final String compilerFilter, boolean bootComplete) {
+ final int compilationReason, boolean bootComplete) {
int numberOfPackagesVisited = 0;
int numberOfPackagesOptimized = 0;
@@ -8974,13 +8964,11 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- String pkgCompilerFilter = compilerFilter;
+ int pkgCompilationReason = compilationReason;
if (useProfileForDexopt) {
// Use background dexopt mode to try and use the profile. Note that this does not
// guarantee usage of the profile.
- pkgCompilerFilter =
- PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
- PackageManagerService.REASON_BACKGROUND_DEXOPT);
+ pkgCompilationReason = PackageManagerService.REASON_BACKGROUND_DEXOPT;
}
// checkProfiles is false to avoid merging profiles during boot which
@@ -8991,7 +8979,7 @@ public class PackageManagerService extends IPackageManager.Stub
int dexoptFlags = bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0;
int primaryDexOptStaus = performDexOptTraced(new DexoptOptions(
pkg.packageName,
- pkgCompilerFilter,
+ pkgCompilationReason,
dexoptFlags));
switch (primaryDexOptStaus) {
@@ -9092,8 +9080,8 @@ public class PackageManagerService extends IPackageManager.Stub
int flags = (checkProfiles ? DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES : 0) |
(force ? DexoptOptions.DEXOPT_FORCE : 0) |
(bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0);
- return performDexOpt(new DexoptOptions(packageName, targetCompilerFilter,
- splitName, flags));
+ return performDexOpt(new DexoptOptions(packageName, REASON_UNKNOWN,
+ targetCompilerFilter, splitName, flags));
}
/**
@@ -9202,7 +9190,8 @@ public class PackageManagerService extends IPackageManager.Stub
final String[] instructionSets = getAppDexInstructionSets(p.applicationInfo);
if (!deps.isEmpty()) {
DexoptOptions libraryOptions = new DexoptOptions(options.getPackageName(),
- options.getCompilerFilter(), options.getSplitName(),
+ options.getCompilationReason(), options.getCompilerFilter(),
+ options.getSplitName(),
options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY);
for (PackageParser.Package depPackage : deps) {
// TODO: Analyze and investigate if we (should) profile libraries.
@@ -16574,17 +16563,7 @@ public class PackageManagerService extends IPackageManager.Stub
PackageInstalledInfo res, UserHandle user, int installReason) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
- String pkgName = pkg.packageName;
- synchronized (mPackages) {
- //write settings. the installStatus will be incomplete at this stage.
- //note that the new package setting would have already been
- //added to mPackages. It hasn't been persisted yet.
- mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_INCOMPLETE);
- // TODO: Remove this write? It's also written at the end of this method
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings");
- mSettings.writeLPr();
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
+ final String pkgName = pkg.packageName;
if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.codePath);
synchronized (mPackages) {
@@ -16665,7 +16644,6 @@ public class PackageManagerService extends IPackageManager.Stub
res.name = pkgName;
res.uid = pkg.applicationInfo.uid;
res.pkg = pkg;
- mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE);
mSettings.setInstallerPackageName(pkgName, installerPackageName);
res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
//to update install status
@@ -18751,7 +18729,7 @@ public class PackageManagerService extends IPackageManager.Stub
return true;
}
- private final class ClearStorageConnection implements ServiceConnection {
+ private static final class ClearStorageConnection implements ServiceConnection {
IMediaContainerService mContainerService;
@Override
@@ -20666,10 +20644,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
@Override
public String getInstallerPackageName(String packageName) {
final int callingUid = Binder.getCallingUid();
- if (getInstantAppPackageName(callingUid) != null) {
- return null;
- }
- // reader
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
@@ -20974,7 +20948,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
pw.println(" check-permission <permission> <package> [<user>]: does pkg hold perm?");
pw.println(" dexopt: dump dexopt state");
pw.println(" compiler-stats: dump compiler statistics");
- pw.println(" enabled-overlays: dump list of enabled overlay packages");
pw.println(" service-permissions: dump permissions required by services");
pw.println(" <package.name>: info about given package");
return;
@@ -21462,35 +21435,37 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
// the given package is involved with.
if (dumpState.onTitlePrinted()) pw.println();
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
- ipw.println();
- ipw.println("Frozen packages:");
- ipw.increaseIndent();
- if (mFrozenPackages.size() == 0) {
- ipw.println("(none)");
- } else {
- for (int i = 0; i < mFrozenPackages.size(); i++) {
- ipw.println(mFrozenPackages.valueAt(i));
+ try (final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120)) {
+ ipw.println();
+ ipw.println("Frozen packages:");
+ ipw.increaseIndent();
+ if (mFrozenPackages.size() == 0) {
+ ipw.println("(none)");
+ } else {
+ for (int i = 0; i < mFrozenPackages.size(); i++) {
+ ipw.println(mFrozenPackages.valueAt(i));
+ }
}
+ ipw.decreaseIndent();
}
- ipw.decreaseIndent();
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_VOLUMES) && packageName == null) {
if (dumpState.onTitlePrinted()) pw.println();
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
- ipw.println();
- ipw.println("Loaded volumes:");
- ipw.increaseIndent();
- if (mLoadedVolumes.size() == 0) {
- ipw.println("(none)");
- } else {
- for (int i = 0; i < mLoadedVolumes.size(); i++) {
- ipw.println(mLoadedVolumes.valueAt(i));
+ try (final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120)) {
+ ipw.println();
+ ipw.println("Loaded volumes:");
+ ipw.increaseIndent();
+ if (mLoadedVolumes.size() == 0) {
+ ipw.println("(none)");
+ } else {
+ for (int i = 0; i < mLoadedVolumes.size(); i++) {
+ ipw.println(mLoadedVolumes.valueAt(i));
+ }
}
+ ipw.decreaseIndent();
}
- ipw.decreaseIndent();
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS)
@@ -21619,61 +21594,63 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
private void dumpDexoptStateLPr(PrintWriter pw, String packageName) {
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
- ipw.println();
- ipw.println("Dexopt state:");
- ipw.increaseIndent();
- Collection<PackageParser.Package> packages = null;
- if (packageName != null) {
- PackageParser.Package targetPackage = mPackages.get(packageName);
- if (targetPackage != null) {
- packages = Collections.singletonList(targetPackage);
+ try (final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ")) {
+ ipw.println();
+ ipw.println("Dexopt state:");
+ ipw.increaseIndent();
+ Collection<PackageParser.Package> packages = null;
+ if (packageName != null) {
+ PackageParser.Package targetPackage = mPackages.get(packageName);
+ if (targetPackage != null) {
+ packages = Collections.singletonList(targetPackage);
+ } else {
+ ipw.println("Unable to find package: " + packageName);
+ return;
+ }
} else {
- ipw.println("Unable to find package: " + packageName);
- return;
+ packages = mPackages.values();
}
- } else {
- packages = mPackages.values();
- }
- for (PackageParser.Package pkg : packages) {
- ipw.println("[" + pkg.packageName + "]");
- ipw.increaseIndent();
- mPackageDexOptimizer.dumpDexoptState(ipw, pkg,
- mDexManager.getPackageUseInfoOrDefault(pkg.packageName));
- ipw.decreaseIndent();
+ for (PackageParser.Package pkg : packages) {
+ ipw.println("[" + pkg.packageName + "]");
+ ipw.increaseIndent();
+ mPackageDexOptimizer.dumpDexoptState(ipw, pkg,
+ mDexManager.getPackageUseInfoOrDefault(pkg.packageName));
+ ipw.decreaseIndent();
+ }
}
}
private void dumpCompilerStatsLPr(PrintWriter pw, String packageName) {
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
- ipw.println();
- ipw.println("Compiler stats:");
- ipw.increaseIndent();
- Collection<PackageParser.Package> packages = null;
- if (packageName != null) {
- PackageParser.Package targetPackage = mPackages.get(packageName);
- if (targetPackage != null) {
- packages = Collections.singletonList(targetPackage);
+ try (final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ")) {
+ ipw.println();
+ ipw.println("Compiler stats:");
+ ipw.increaseIndent();
+ Collection<PackageParser.Package> packages = null;
+ if (packageName != null) {
+ PackageParser.Package targetPackage = mPackages.get(packageName);
+ if (targetPackage != null) {
+ packages = Collections.singletonList(targetPackage);
+ } else {
+ ipw.println("Unable to find package: " + packageName);
+ return;
+ }
} else {
- ipw.println("Unable to find package: " + packageName);
- return;
+ packages = mPackages.values();
}
- } else {
- packages = mPackages.values();
- }
- for (PackageParser.Package pkg : packages) {
- ipw.println("[" + pkg.packageName + "]");
- ipw.increaseIndent();
+ for (PackageParser.Package pkg : packages) {
+ ipw.println("[" + pkg.packageName + "]");
+ ipw.increaseIndent();
- CompilerStats.PackageStats stats = getCompilerPackageStats(pkg.packageName);
- if (stats == null) {
- ipw.println("(No recorded stats)");
- } else {
- stats.dump(ipw);
+ CompilerStats.PackageStats stats = getCompilerPackageStats(pkg.packageName);
+ if (stats == null) {
+ ipw.println("(No recorded stats)");
+ } else {
+ stats.dump(ipw);
+ }
+ ipw.decreaseIndent();
}
- ipw.decreaseIndent();
}
}
@@ -22252,8 +22229,16 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
Slog.e(TAG, "Failed to create app data for " + packageName + ": " + e);
}
}
- // Prepare the application profiles.
- mArtManagerService.prepareAppProfiles(pkg, userId);
+ // Prepare the application profiles only for upgrades and first boot (so that we don't
+ // repeat the same operation at each boot).
+ // We only have to cover the upgrade and first boot here because for app installs we
+ // prepare the profiles before invoking dexopt (in installPackageLI).
+ //
+ // We also have to cover non system users because we do not call the usual install package
+ // methods for them.
+ if (mIsUpgrade || mFirstBoot || (userId != UserHandle.USER_SYSTEM)) {
+ mArtManagerService.prepareAppProfiles(pkg, userId);
+ }
if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) {
// TODO: mark this structure as dirty so we persist it!
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index 19b0d9bc4b90..fce828581c54 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -123,4 +123,14 @@ public class PackageManagerServiceCompilerMapping {
return value;
}
+
+ public static String getReasonName(int reason) {
+ if (reason == PackageManagerService.REASON_UNKNOWN) {
+ return "unknown";
+ }
+ if (reason < 0 || reason >= REASON_STRINGS.length) {
+ throw new IllegalArgumentException("reason " + reason + " invalid");
+ }
+ return REASON_STRINGS[reason];
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 758c9d56d32a..d2ef67b74fef 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -34,6 +34,7 @@ import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
+import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageManager;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
@@ -89,12 +90,7 @@ import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.WeakHashMap;
+import java.util.*;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
@@ -235,6 +231,8 @@ class PackageManagerShellCommand extends ShellCommand {
return runSetHarmfulAppWarning();
case "get-harmful-app-warning":
return runGetHarmfulAppWarning();
+ case "uninstall-system-updates":
+ return uninstallSystemUpdates();
default: {
String nextArg = getNextArg();
if (nextArg == null) {
@@ -257,6 +255,47 @@ class PackageManagerShellCommand extends ShellCommand {
return -1;
}
+ private int uninstallSystemUpdates() {
+ final PrintWriter pw = getOutPrintWriter();
+ List<String> failedUninstalls = new LinkedList<>();
+ try {
+ final ParceledListSlice<ApplicationInfo> packages =
+ mInterface.getInstalledApplications(
+ PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
+ final IPackageInstaller installer = mInterface.getPackageInstaller();
+ List<ApplicationInfo> list = packages.getList();
+ for (ApplicationInfo info : list) {
+ if (info.isUpdatedSystemApp()) {
+ pw.println("Uninstalling updates to " + info.packageName + "...");
+ final LocalIntentReceiver receiver = new LocalIntentReceiver();
+ installer.uninstall(new VersionedPackage(info.packageName,
+ info.versionCode), null /*callerPackageName*/, 0 /* flags */,
+ receiver.getIntentSender(), 0);
+
+ final Intent result = receiver.getResult();
+ final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE);
+ if (status != PackageInstaller.STATUS_SUCCESS) {
+ failedUninstalls.add(info.packageName);
+ }
+ }
+ }
+ } catch (RemoteException e) {
+ pw.println("Failure ["
+ + e.getClass().getName() + " - "
+ + e.getMessage() + "]");
+ return 0;
+ }
+ if (!failedUninstalls.isEmpty()) {
+ pw.println("Failure [Couldn't uninstall packages: "
+ + TextUtils.join(", ", failedUninstalls)
+ + "]");
+ return 0;
+ }
+ pw.println("Success");
+ return 1;
+ }
+
private void setParamsSize(InstallParams params, String inPath) {
if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {
final ParcelFileDescriptor fd = openFileForSystem(inPath, "r");
@@ -2705,6 +2744,10 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" get-harmful-app-warning [--user <USER_ID>] <PACKAGE>");
pw.println(" Return the harmful app warning message for the given app, if present");
pw.println();
+ pw.println(" uninstall-system-updates");
+ pw.println(" Remove updates to all system applications and fall back to their /system " +
+ "version.");
+ pw.println();
Intent.printIntentArgsHelp(pw , "");
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index f14a684b3865..a0ed12611e48 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -46,19 +46,6 @@ public abstract class PackageSettingBase extends SettingBase {
private static final int[] EMPTY_INT_ARRAY = new int[0];
- /**
- * Indicates the state of installation. Used by PackageManager to figure out
- * incomplete installations. Say a package is being installed (the state is
- * set to PKG_INSTALL_INCOMPLETE) and remains so till the package
- * installation is successful or unsuccessful in which case the
- * PackageManager will no longer maintain state information associated with
- * the package. If some exception(like device freeze or battery being pulled
- * out) occurs during installation of a package, the PackageManager needs
- * this information to clean up the previously failed installation.
- */
- static final int PKG_INSTALL_COMPLETE = 1;
- static final int PKG_INSTALL_INCOMPLETE = 0;
-
public final String name;
final String realName;
@@ -122,8 +109,6 @@ public abstract class PackageSettingBase extends SettingBase {
// started until explicitly launched by the user.
private final SparseArray<PackageUserState> userState = new SparseArray<PackageUserState>();
- int installStatus = PKG_INSTALL_COMPLETE;
-
/**
* Non-persisted value. During an "upgrade without restart", we need the set
* of all previous code paths so we can surgically add the new APKs to the
@@ -209,14 +194,6 @@ public abstract class PackageSettingBase extends SettingBase {
return volumeUuid;
}
- public void setInstallStatus(int newStatus) {
- installStatus = newStatus;
- }
-
- public int getInstallStatus() {
- return installStatus;
- }
-
public void setTimeStamp(long newStamp) {
timeStamp = newStamp;
}
@@ -260,7 +237,6 @@ public abstract class PackageSettingBase extends SettingBase {
cpuAbiOverrideString = orig.cpuAbiOverrideString;
firstInstallTime = orig.firstInstallTime;
installPermissionsFixed = orig.installPermissionsFixed;
- installStatus = orig.installStatus;
installerPackageName = orig.installerPackageName;
isOrphaned = orig.isOrphaned;
keySetData = orig.keySetData;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index b6e1534d6dcb..a38cbda245ca 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -455,15 +455,6 @@ public final class Settings {
return mRenamedPackages.put(pkgName, origPkgName);
}
- void setInstallStatus(String pkgName, final int status) {
- PackageSetting p = mPackages.get(pkgName);
- if(p != null) {
- if(p.getInstallStatus() != status) {
- p.setInstallStatus(status);
- }
- }
- }
-
void applyPendingPermissionGrantsLPw(String packageName, int userId) {
ArrayMap<String, ArraySet<RestoredPermissionGrant>> grantsByPackage =
mRestoredUserGrants.get(userId);
@@ -2839,9 +2830,6 @@ public final class Settings {
if (pkg.uidError) {
serializer.attribute(null, "uidError", "true");
}
- if (pkg.installStatus == PackageSettingBase.PKG_INSTALL_INCOMPLETE) {
- serializer.attribute(null, "installStatus", "false");
- }
if (pkg.installerPackageName != null) {
serializer.attribute(null, "installer", pkg.installerPackageName);
}
@@ -2912,20 +2900,6 @@ public final class Settings {
bp.writeLPr(serializer);
}
- ArrayList<PackageSetting> getListOfIncompleteInstallPackagesLPr() {
- final ArraySet<String> kList = new ArraySet<String>(mPackages.keySet());
- final Iterator<String> its = kList.iterator();
- final ArrayList<PackageSetting> ret = new ArrayList<PackageSetting>();
- while (its.hasNext()) {
- final String key = its.next();
- final PackageSetting ps = mPackages.get(key);
- if (ps.getInstallStatus() == PackageSettingBase.PKG_INSTALL_INCOMPLETE) {
- ret.add(ps);
- }
- }
- return ret;
- }
-
void addPackageToCleanLPw(PackageCleanItem pkg) {
if (!mPackagesToBeCleaned.contains(pkg)) {
mPackagesToBeCleaned.add(pkg);
@@ -3874,15 +3848,6 @@ public final class Settings {
mInstallerPackages.add(installerPackageName);
}
- final String installStatusStr = parser.getAttributeValue(null, "installStatus");
- if (installStatusStr != null) {
- if (installStatusStr.equalsIgnoreCase("false")) {
- packageSetting.installStatus = PackageSettingBase.PKG_INSTALL_INCOMPLETE;
- } else {
- packageSetting.installStatus = PackageSettingBase.PKG_INSTALL_COMPLETE;
- }
- }
-
int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -4668,10 +4633,15 @@ public final class Settings {
pw.print(prefix); pw.print(" signatures="); pw.println(ps.signatures);
pw.print(prefix); pw.print(" installPermissionsFixed=");
pw.print(ps.installPermissionsFixed);
- pw.print(" installStatus="); pw.println(ps.installStatus);
+ pw.println();
pw.print(prefix); pw.print(" pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC);
pw.println();
+ if (ps.pkg.mOverlayTarget != null) {
+ pw.print(prefix); pw.print(" overlayTarget="); pw.println(ps.pkg.mOverlayTarget);
+ pw.print(prefix); pw.print(" overlayCategory="); pw.println(ps.pkg.mOverlayCategory);
+ }
+
if (ps.pkg != null && ps.pkg.permissions != null && ps.pkg.permissions.size() > 0) {
final ArrayList<PackageParser.Permission> perms = ps.pkg.permissions;
pw.print(prefix); pw.println(" declared permissions:");
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a0577b15736b..0eeaf661635d 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1486,6 +1486,23 @@ public class UserManagerService extends IUserManager.Stub {
return restrictions != null && restrictions.getBoolean(restrictionKey);
}
+ /** @return if any user has the given restriction. */
+ @Override
+ public boolean hasUserRestrictionOnAnyUser(String restrictionKey) {
+ if (!UserRestrictionsUtils.isValidRestriction(restrictionKey)) {
+ return false;
+ }
+ final List<UserInfo> users = getUsers(/* excludeDying= */ true);
+ for (int i = 0; i < users.size(); i++) {
+ final int userId = users.get(i).id;
+ Bundle restrictions = getEffectiveUserRestrictions(userId);
+ if (restrictions != null && restrictions.getBoolean(restrictionKey)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* @hide
*
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 23185d7fb5ab..41570c48c474 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -33,6 +33,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.provider.Settings;
+import android.provider.Settings.Global;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.util.Log;
@@ -581,6 +582,15 @@ public class UserRestrictionsUtils {
Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, "0");
}
break;
+ case UserManager.DISALLOW_CONFIG_LOCATION:
+ // When DISALLOW_CONFIG_LOCATION is set on any user, we undo the global
+ // kill switch.
+ if (newValue) {
+ android.provider.Settings.Global.putString(
+ context.getContentResolver(),
+ Global.LOCATION_GLOBAL_KILL_SWITCH, "0");
+ }
+ break;
}
} finally {
Binder.restoreCallingIdentity(id);
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 0e2730cbd944..3e63fb42f0ef 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -549,13 +549,12 @@ public class DexManager {
mPackageDexUsage.maybeWriteAsync();
}
- // Try to optimize the package according to the install reason.
- String compilerFilter = PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
- PackageManagerService.REASON_INSTALL);
DexUseInfo dexUseInfo = mPackageDexUsage.getPackageUseInfo(searchResult.mOwningPackageName)
.getDexUseInfoMap().get(dexPath);
- DexoptOptions options = new DexoptOptions(info.packageName, compilerFilter, /*flags*/0);
+ // Try to optimize the package according to the install reason.
+ DexoptOptions options = new DexoptOptions(info.packageName,
+ PackageManagerService.REASON_INSTALL, /*flags*/0);
int result = mPackageDexOptimizer.dexOptSecondaryDexPath(info, dexPath, dexUseInfo,
options);
diff --git a/services/core/java/com/android/server/pm/dex/DexoptOptions.java b/services/core/java/com/android/server/pm/dex/DexoptOptions.java
index d4f95cb6b99f..a7a7686b2a6b 100644
--- a/services/core/java/com/android/server/pm/dex/DexoptOptions.java
+++ b/services/core/java/com/android/server/pm/dex/DexoptOptions.java
@@ -77,15 +77,21 @@ public final class DexoptOptions {
// It only applies for primary apk and it's always null if mOnlySecondaryDex is true.
private final String mSplitName;
+ // The reason for invoking dexopt (see PackageManagerService.REASON_* constants).
+ // A -1 value denotes an unknown reason.
+ private final int mCompilationReason;
+
public DexoptOptions(String packageName, String compilerFilter, int flags) {
- this(packageName, compilerFilter, /*splitName*/ null, flags);
+ this(packageName, /*compilationReason*/ -1, compilerFilter, /*splitName*/ null, flags);
}
- public DexoptOptions(String packageName, int compilerReason, int flags) {
- this(packageName, getCompilerFilterForReason(compilerReason), flags);
+ public DexoptOptions(String packageName, int compilationReason, int flags) {
+ this(packageName, compilationReason, getCompilerFilterForReason(compilationReason),
+ /*splitName*/ null, flags);
}
- public DexoptOptions(String packageName, String compilerFilter, String splitName, int flags) {
+ public DexoptOptions(String packageName, int compilationReason, String compilerFilter,
+ String splitName, int flags) {
int validityMask =
DEXOPT_CHECK_FOR_PROFILES_UPDATES |
DEXOPT_FORCE |
@@ -104,6 +110,7 @@ public final class DexoptOptions {
mCompilerFilter = compilerFilter;
mFlags = flags;
mSplitName = splitName;
+ mCompilationReason = compilationReason;
}
public String getPackageName() {
@@ -157,4 +164,8 @@ public final class DexoptOptions {
public int getFlags() {
return mFlags;
}
+
+ public int getCompilationReason() {
+ return mCompilationReason;
+ }
}
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 63087669b2f6..4abcce16f777 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -16,7 +16,7 @@
package com.android.server.pm.permission;
-import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
+import static android.os.Process.FIRST_APPLICATION_UID;
import android.Manifest;
import android.annotation.NonNull;
@@ -25,18 +25,18 @@ import android.app.ActivityManager;
import android.app.DownloadManager;
import android.app.admin.DevicePolicyManager;
import android.companion.CompanionDeviceManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageList;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.PackageManagerInternal.PackagesProvider;
+import android.content.pm.PackageManagerInternal.SyncAdapterPackagesProvider;
import android.content.pm.PackageParser;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
-import android.content.pm.PackageManagerInternal.PackagesProvider;
-import android.content.pm.PackageManagerInternal.SyncAdapterPackagesProvider;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Binder;
@@ -52,15 +52,18 @@ import android.provider.CalendarContract;
import android.provider.ContactsContract;
import android.provider.MediaStore;
import android.provider.Telephony.Sms.Intents;
-import android.telephony.TelephonyManager;
import android.security.Credentials;
+import android.service.textclassifier.TextClassifierService;
+import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
import android.util.Xml;
+
import com.android.internal.util.XmlUtils;
import com.android.server.LocalServices;
+import com.android.server.pm.PackageManagerService;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -71,14 +74,11 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import static android.os.Process.FIRST_APPLICATION_UID;
-
/**
* This class is the policy for granting runtime permissions to
* platform components and default handlers in the system such
@@ -433,6 +433,13 @@ public final class DefaultPermissionGrantPolicy {
grantRuntimePermissions(storagePackage, STORAGE_PERMISSIONS, true, userId);
}
+ // Container service
+ PackageParser.Package containerPackage = getSystemPackage(
+ PackageManagerService.DEFAULT_CONTAINER_PACKAGE);
+ if (containerPackage != null) {
+ grantRuntimePermissions(containerPackage, STORAGE_PERMISSIONS, true, userId);
+ }
+
// CertInstaller
Intent certInstallerIntent = new Intent(Credentials.INSTALL_ACTION);
PackageParser.Package certInstallerPackage = getDefaultSystemHandlerActivityPackage(
@@ -821,6 +828,24 @@ public final class DefaultPermissionGrantPolicy {
STORAGE_PERMISSIONS, true, userId);
}
+ // TextClassifier Service
+ ComponentName textClassifierComponent =
+ TextClassifierService.getServiceComponentName(mContext);
+ if (textClassifierComponent != null) {
+ Intent textClassifierServiceIntent = new Intent(TextClassifierService.SERVICE_INTERFACE)
+ .setComponent(textClassifierComponent);
+ PackageParser.Package textClassifierPackage =
+ getDefaultSystemHandlerServicePackage(textClassifierServiceIntent, userId);
+ if (textClassifierPackage != null
+ && doesPackageSupportRuntimePermissions(textClassifierPackage)) {
+ grantRuntimePermissions(textClassifierPackage, PHONE_PERMISSIONS, true, userId);
+ grantRuntimePermissions(textClassifierPackage, SMS_PERMISSIONS, true, userId);
+ grantRuntimePermissions(textClassifierPackage, CALENDAR_PERMISSIONS, true, userId);
+ grantRuntimePermissions(textClassifierPackage, LOCATION_PERMISSIONS, true, userId);
+ grantRuntimePermissions(textClassifierPackage, CONTACTS_PERMISSIONS, true, userId);
+ }
+ }
+
if (mPermissionGrantedCallback != null) {
mPermissionGrantedCallback.onDefaultRuntimePermissionsGranted(userId);
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 0502848d698e..e77dd7b90d5d 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1326,30 +1326,38 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// When interactive, we're already awake.
// Wait for a long press or for the button to be released to decide what to do.
if (hasLongPressOnPowerBehavior()) {
- Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
- msg.setAsynchronous(true);
- mHandler.sendMessageDelayed(msg,
- ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
+ if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
+ powerLongPress();
+ } else {
+ Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
+ msg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(msg,
+ ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
- if (hasVeryLongPressOnPowerBehavior()) {
- Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
- longMsg.setAsynchronous(true);
- mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
+ if (hasVeryLongPressOnPowerBehavior()) {
+ Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
+ longMsg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
+ }
}
}
} else {
wakeUpFromPowerKey(event.getDownTime());
if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
- Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
- msg.setAsynchronous(true);
- mHandler.sendMessageDelayed(msg,
- ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
+ if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
+ powerLongPress();
+ } else {
+ Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
+ msg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(msg,
+ ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
- if (hasVeryLongPressOnPowerBehavior()) {
- Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
- longMsg.setAsynchronous(true);
- mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
+ if (hasVeryLongPressOnPowerBehavior()) {
+ Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
+ longMsg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
+ }
}
mBeganFromNonInteractive = true;
@@ -5218,9 +5226,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
final int cutoutMode = attrs.layoutInDisplayCutoutMode;
+ final boolean attachedInParent = attached != null && !layoutInScreen;
// Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
// the cutout safe zone.
- if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
+ // Windows that are attached to a parent and laid out in said parent are already avoiding
+ // the cutout according to that parent and don't need to be further constrained.
+ if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS && !attachedInParent) {
final Rect displayCutoutSafeExceptMaybeTop = mTmpRect;
displayCutoutSafeExceptMaybeTop.set(displayFrames.mDisplayCutoutSafe);
if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index 941cd4441e23..efcadadce3f9 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -19,6 +19,8 @@ package com.android.server.policy.keyguard;
import android.app.ActivityManager;
import android.content.Context;
import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.security.IKeystoreService;
import android.util.Slog;
import com.android.internal.policy.IKeyguardService;
@@ -51,11 +53,16 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub {
private final LockPatternUtils mLockPatternUtils;
private final StateCallback mCallback;
+ IKeystoreService mKeystoreService;
+
public KeyguardStateMonitor(Context context, IKeyguardService service, StateCallback callback) {
mLockPatternUtils = new LockPatternUtils(context);
mCurrentUserId = ActivityManager.getCurrentUser();
mCallback = callback;
+ mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager
+ .getService("android.security.keystore"));
+
try {
service.addStateMonitorCallback(this);
} catch (RemoteException e) {
@@ -86,6 +93,12 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub {
@Override // Binder interface
public void onShowingStateChanged(boolean showing) {
mIsShowing = showing;
+
+ if (showing) try {
+ mKeystoreService.lock(mCurrentUserId); // as long as this doesn't recur...
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error locking keystore", e);
+ }
}
@Override // Binder interface
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
index 37df94fee207..5d76329eb8a1 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
@@ -15,6 +15,7 @@
*/
package com.android.server.power.batterysaver;
+import android.metrics.LogMaker;
import android.os.BatteryManagerInternal;
import android.os.SystemClock;
import android.util.ArrayMap;
@@ -23,6 +24,8 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.power.BatterySaverPolicy;
@@ -43,6 +46,9 @@ public class BatterySavingStats {
private static final boolean DEBUG = BatterySaverPolicy.DEBUG;
+ @VisibleForTesting
+ static final boolean SEND_TRON_EVENTS = true;
+
private final Object mLock = new Object();
/** Whether battery saver is on or off. */
@@ -132,15 +138,6 @@ public class BatterySavingStats {
}
}
- @VisibleForTesting
- static final String COUNTER_POWER_PERCENT_PREFIX = "battery_saver_stats_percent_";
-
- @VisibleForTesting
- static final String COUNTER_POWER_MILLIAMPS_PREFIX = "battery_saver_stats_milliamps_";
-
- @VisibleForTesting
- static final String COUNTER_TIME_SECONDS_PREFIX = "battery_saver_stats_seconds_";
-
private static BatterySavingStats sInstance;
private BatteryManagerInternal mBatteryManagerInternal;
@@ -427,10 +424,9 @@ public class BatterySavingStats {
if (stateChanging) {
if (mLastState >= 0) {
final long deltaTime = now - mStartTime;
- final int deltaBattery = mStartBatteryLevel - batteryLevel;
- final int deltaPercent = mStartPercent - batteryPercent;
- report(mLastState, deltaTime, deltaBattery, deltaPercent);
+ report(mLastState, deltaTime, mStartBatteryLevel, mStartPercent,
+ batteryLevel, batteryPercent);
}
mStartTime = now;
mStartBatteryLevel = batteryLevel;
@@ -439,23 +435,28 @@ public class BatterySavingStats {
mLastState = newState;
}
- String getCounterSuffix(int state) {
- final boolean batterySaver =
+ void report(int state, long deltaTimeMs,
+ int startBatteryLevelUa, int startBatteryLevelPercent,
+ int endBatteryLevelUa, int endBatteryLevelPercent) {
+ if (!SEND_TRON_EVENTS) {
+ return;
+ }
+ final boolean batterySaverOn =
BatterySaverState.fromIndex(state) != BatterySaverState.OFF;
final boolean interactive =
InteractiveState.fromIndex(state) != InteractiveState.NON_INTERACTIVE;
- if (batterySaver) {
- return interactive ? "11" : "10";
- } else {
- return interactive ? "01" : "00";
- }
- }
- void report(int state, long deltaTimeMs, int deltaBatteryUa, int deltaPercent) {
- final String suffix = getCounterSuffix(state);
- mMetricsLogger.count(COUNTER_POWER_MILLIAMPS_PREFIX + suffix, deltaBatteryUa / 1000);
- mMetricsLogger.count(COUNTER_POWER_PERCENT_PREFIX + suffix, deltaPercent);
- mMetricsLogger.count(COUNTER_TIME_SECONDS_PREFIX + suffix, (int) (deltaTimeMs / 1000));
+ final LogMaker logMaker = new LogMaker(MetricsProto.MetricsEvent.BATTERY_SAVER)
+ .setSubtype(batterySaverOn ? 1 : 0)
+ .addTaggedData(MetricsEvent.FIELD_INTERACTIVE, interactive ? 1 : 0)
+ .addTaggedData(MetricsEvent.FIELD_DURATION_MILLIS, deltaTimeMs)
+ .addTaggedData(MetricsEvent.FIELD_START_BATTERY_UA, startBatteryLevelUa)
+ .addTaggedData(MetricsEvent.FIELD_START_BATTERY_PERCENT,
+ startBatteryLevelPercent)
+ .addTaggedData(MetricsEvent.FIELD_END_BATTERY_UA, endBatteryLevelUa)
+ .addTaggedData(MetricsEvent.FIELD_END_BATTERY_PERCENT, endBatteryLevelPercent);
+
+ mMetricsLogger.write(logMaker);
}
}
}
diff --git a/services/core/java/com/android/server/stats/OWNERS b/services/core/java/com/android/server/stats/OWNERS
new file mode 100644
index 000000000000..8d7f8822f78e
--- /dev/null
+++ b/services/core/java/com/android/server/stats/OWNERS
@@ -0,0 +1,9 @@
+bookatz@google.com
+cjyu@google.com
+dwchen@google.com
+joeo@google.com
+singhtejinder@google.com
+stlafon@google.com
+yaochen@google.com
+yanglu@google.com
+yro@google.com \ No newline at end of file
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 4bc94047b24e..d6359b8cbee3 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -16,8 +16,10 @@
package com.android.server.stats;
import android.annotation.Nullable;
+import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
import android.app.PendingIntent;
+import android.app.ProcessMemoryState;
import android.app.StatsManager;
import android.bluetooth.BluetoothActivityEnergyInfo;
import android.bluetooth.BluetoothAdapter;
@@ -128,7 +130,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
synchronized (sStatsdLock) {
sStatsd = fetchStatsdService();
if (sStatsd == null) {
- Slog.w(TAG, "Could not access statsd");
+ Slog.w(TAG, "Could not access statsd for UserUpdateReceiver");
return;
}
try {
@@ -143,7 +145,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
};
mShutdownEventReceiver = new ShutdownEventReceiver();
- Slog.w(TAG, "Registered receiver for ACTION_PACKAGE_REPLACE AND ADDED.");
+ if (DEBUG) Slog.d(TAG, "Registered receiver for ACTION_PACKAGE_REPLACED and ADDED.");
PowerProfile powerProfile = new PowerProfile(context);
final int numClusters = powerProfile.getNumCpuClusters();
mKernelCpuSpeedReaders = new KernelCpuSpeedReader[numClusters];
@@ -172,7 +174,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
public void sendSubscriberBroadcast(IBinder intentSenderBinder, long configUid, long configKey,
long subscriptionId, long subscriptionRuleId,
StatsDimensionsValue dimensionsValue) {
- if (DEBUG) Slog.d(TAG, "Statsd requested to sendSubscriberBroadcast.");
enforceCallingPermission();
IntentSender intentSender = new IntentSender(intentSenderBinder);
Intent intent = new Intent()
@@ -181,16 +182,16 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
.putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_ID, subscriptionId)
.putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_RULE_ID, subscriptionRuleId)
.putExtra(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE, dimensionsValue);
+ if (DEBUG) {
+ Slog.d(TAG, String.format("Statsd sendSubscriberBroadcast with params {%d %d %d %d %s}",
+ configUid, configKey, subscriptionId,
+ subscriptionRuleId, dimensionsValue));
+ }
try {
intentSender.sendIntent(mContext, CODE_SUBSCRIBER_BROADCAST, intent, null, null);
} catch (IntentSender.SendIntentException e) {
Slog.w(TAG, "Unable to send using IntentSender from uid " + configUid
+ "; presumably it had been cancelled.");
- if (DEBUG) {
- Slog.d(TAG, String.format("SubscriberBroadcast params {%d %d %d %d %s}",
- configUid, configKey, subscriptionId,
- subscriptionRuleId, dimensionsValue));
- }
}
}
@@ -217,12 +218,12 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
PackageManager pm = context.getPackageManager();
final List<UserInfo> users = um.getUsers(true);
if (DEBUG) {
- Slog.w(TAG, "Iterating over " + users.size() + " profiles.");
+ Slog.d(TAG, "Iterating over " + users.size() + " profiles.");
}
- List<Integer> uids = new ArrayList();
- List<Long> versions = new ArrayList();
- List<String> apps = new ArrayList();
+ List<Integer> uids = new ArrayList<>();
+ List<Long> versions = new ArrayList<>();
+ List<String> apps = new ArrayList<>();
// Add in all the apps for every user/profile.
for (UserInfo profile : users) {
@@ -238,7 +239,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
sStatsd.informAllUidData(toIntArray(uids), toLongArray(versions), apps.toArray(new
String[apps.size()]));
if (DEBUG) {
- Slog.w(TAG, "Sent data for " + uids.size() + " apps");
+ Slog.d(TAG, "Sent data for " + uids.size() + " apps");
}
}
@@ -361,9 +362,11 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
if (DEBUG) Slog.d(TAG, "Setting anomaly alarm for " + timestampMs);
final long callingToken = Binder.clearCallingIdentity();
try {
- // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens.
+ // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
+ // only fire when it awakens.
+ // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
// AlarmManager will automatically cancel any previous mAnomalyAlarmIntent alarm.
- mAlarmManager.setExact(AlarmManager.RTC, timestampMs, mAnomalyAlarmIntent);
+ mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, mAnomalyAlarmIntent);
} finally {
Binder.restoreCallingIdentity(callingToken);
}
@@ -388,10 +391,12 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
Slog.d(TAG, "Setting pulling alarm for " + timestampMs + " every " + intervalMs + "ms");
final long callingToken = Binder.clearCallingIdentity();
try {
- // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens.
+ // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
+ // only fire when it awakens.
// This alarm is inexact, leaving its exactness completely up to the OS optimizations.
// TODO: totally inexact means that stats per bucket could be quite off. Is this okay?
- mAlarmManager.setRepeating(AlarmManager.RTC, timestampMs, intervalMs, mPullingAlarmIntent);
+ mAlarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, timestampMs, intervalMs,
+ mPullingAlarmIntent);
} finally {
Binder.restoreCallingIdentity(callingToken);
}
@@ -709,6 +714,24 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
pulledData.add(e);
}
+ private void pullProcessMemoryState(int tagId, List<StatsLogEventWrapper> pulledData) {
+ List<ProcessMemoryState> processMemoryStates =
+ LocalServices.getService(ActivityManagerInternal.class)
+ .getMemoryStateForProcesses();
+ for (ProcessMemoryState processMemoryState : processMemoryStates) {
+ StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 8 /* fields */);
+ e.writeInt(processMemoryState.uid);
+ e.writeString(processMemoryState.processName);
+ e.writeInt(processMemoryState.oomScore);
+ e.writeLong(processMemoryState.pgfault);
+ e.writeLong(processMemoryState.pgmajfault);
+ e.writeLong(processMemoryState.rssInBytes);
+ e.writeLong(processMemoryState.cacheInBytes);
+ e.writeLong(processMemoryState.swapInBytes);
+ pulledData.add(e);
+ }
+ }
+
/**
* Pulls various data.
*/
@@ -717,7 +740,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
enforceCallingPermission();
if (DEBUG)
Slog.d(TAG, "Pulling " + tagId);
- List<StatsLogEventWrapper> ret = new ArrayList();
+ List<StatsLogEventWrapper> ret = new ArrayList<>();
switch (tagId) {
case StatsLog.WIFI_BYTES_TRANSFER: {
pullWifiBytesTransfer(tagId, ret);
@@ -771,6 +794,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
pullDiskSpace(tagId, ret);
break;
}
+ case StatsLog.PROCESS_MEMORY_STATE: {
+ pullProcessMemoryState(tagId, ret);
+ break;
+ }
default:
Slog.w(TAG, "No such tagId data as " + tagId);
return null;
@@ -865,7 +892,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
sStatsd = fetchStatsdService();
if (sStatsd == null) {
- Slog.w(TAG, "Could not access statsd");
+ Slog.i(TAG, "Could not yet find statsd to tell it that StatsCompanion is alive.");
return;
}
if (DEBUG) Slog.d(TAG, "Saying hi to statsd");
@@ -905,6 +932,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
} finally {
restoreCallingIdentity(token);
}
+ Slog.i(TAG, "Told statsd that StatsCompanionService is alive.");
} catch (RemoteException e) {
Slog.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
forgetEverything();
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 2bdaa1a66b7e..0d36145c8661 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -78,9 +78,12 @@ import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.GraphicBuffer;
import android.graphics.Path;
+import android.graphics.Picture;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Binder;
@@ -96,11 +99,8 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.AppTransitionAnimationSpec;
-import android.view.DisplayListCanvas;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.RemoteAnimationAdapter;
-import android.view.RenderNode;
-import android.view.ThreadedRenderer;
import android.view.WindowManager.TransitionFlags;
import android.view.WindowManager.TransitionType;
import android.view.animation.AlphaAnimation;
@@ -973,11 +973,8 @@ public class AppTransition implements Dump {
final int width = frame.width();
final int height = frame.height();
- final RenderNode node = RenderNode.create("CrossProfileAppsThumbnail", null);
- node.setLeftTopRightBottom(0, 0, width, height);
- node.setClipToBounds(false);
-
- final DisplayListCanvas canvas = node.start(width, height);
+ final Picture picture = new Picture();
+ final Canvas canvas = picture.beginRecording(width, height);
canvas.drawColor(Color.argb(0.6f, 0, 0, 0));
final int thumbnailSize = mService.mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.cross_profile_apps_thumbnail_size);
@@ -988,10 +985,9 @@ public class AppTransition implements Dump {
(width + thumbnailSize) / 2,
(height + thumbnailSize) / 2);
drawable.draw(canvas);
- node.end(canvas);
+ picture.endRecording();
- return ThreadedRenderer.createHardwareBitmap(node, width, height)
- .createGraphicBufferHandle();
+ return Bitmap.createBitmap(picture).createGraphicBufferHandle();
}
Animation createCrossProfileAppsThumbnailAnimationLocked(Rect appRect) {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index ce3f512deccf..8155656cd5f4 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1766,6 +1766,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
layer += Z_BOOST_BASE;
}
leash.setLayer(layer);
+
+ final DisplayContent dc = getDisplayContent();
+ dc.assignStackOrdering(t);
}
/**
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 41a6e2ba7e69..d22828dba6e7 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3533,39 +3533,47 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
@Override
void assignChildLayers(SurfaceControl.Transaction t) {
+ assignStackOrdering(t);
+ for (int i = 0; i < mChildren.size(); i++) {
+ final TaskStack s = mChildren.get(i);
+ s.assignChildLayers(t);
+ }
+ }
+
+ void assignStackOrdering(SurfaceControl.Transaction t) {
final int HOME_STACK_STATE = 0;
final int NORMAL_STACK_STATE = 1;
final int ALWAYS_ON_TOP_STATE = 2;
int layer = 0;
+ int layerForAnimationLayer = 0;
+
for (int state = 0; state <= ALWAYS_ON_TOP_STATE; state++) {
for (int i = 0; i < mChildren.size(); i++) {
final TaskStack s = mChildren.get(i);
- if (state == HOME_STACK_STATE && s.isActivityTypeHome()) {
- s.assignLayer(t, layer++);
- } else if (state == NORMAL_STACK_STATE && !s.isActivityTypeHome()
- && !s.isAlwaysOnTop()) {
- s.assignLayer(t, layer++);
- if (s.inSplitScreenWindowingMode() && mSplitScreenDividerAnchor != null) {
- t.setLayer(mSplitScreenDividerAnchor, layer++);
- }
- } else if (state == ALWAYS_ON_TOP_STATE && s.isAlwaysOnTop()) {
- s.assignLayer(t, layer++);
+ if (state == HOME_STACK_STATE && !s.isActivityTypeHome()) {
+ continue;
+ } else if (state == NORMAL_STACK_STATE && (s.isActivityTypeHome()
+ || s.isAlwaysOnTop())) {
+ continue;
+ } else if (state == ALWAYS_ON_TOP_STATE && !s.isAlwaysOnTop()) {
+ continue;
+ }
+ s.assignLayer(t, layer++);
+ if (s.inSplitScreenWindowingMode() && mSplitScreenDividerAnchor != null) {
+ t.setLayer(mSplitScreenDividerAnchor, layer++);
+ }
+ if (s.isSelfOrChildAnimating()) {
+ // Ensure the animation layer ends up above the
+ // highest animating stack and no higher.
+ layerForAnimationLayer = layer++;
}
- }
- // The appropriate place for App-Transitions to occur is right
- // above all other animations but still below things in the Picture-and-Picture
- // windowing mode.
- if (state == NORMAL_STACK_STATE && mAppAnimationLayer != null) {
- t.setLayer(mAppAnimationLayer, layer++);
}
}
- for (int i = 0; i < mChildren.size(); i++) {
- final TaskStack s = mChildren.get(i);
- s.assignChildLayers(t);
+ if (mAppAnimationLayer != null) {
+ t.setLayer(mAppAnimationLayer, layerForAnimationLayer);
}
-
}
@Override
@@ -3878,4 +3886,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
super.prepareSurfaces();
}
+
+ void assignStackOrdering(SurfaceControl.Transaction t) {
+ mTaskStackContainers.assignStackOrdering(t);
+ }
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index e869f582ed1f..78dd580259a0 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -24,15 +24,15 @@ import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_W
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import android.app.ActivityManager;
import android.app.ActivityManager.TaskSnapshot;
import android.app.WindowConfiguration;
-import android.graphics.GraphicBuffer;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
+import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
import android.view.IRecentsAnimationController;
@@ -41,6 +41,7 @@ import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+import com.google.android.collect.Sets;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -59,6 +60,7 @@ public class RecentsAnimationController {
private final IRecentsAnimationRunner mRunner;
private final RecentsAnimationCallbacks mCallbacks;
private final ArrayList<TaskAnimationAdapter> mPendingAnimations = new ArrayList<>();
+ private final int mDisplayId;
// The recents component app token that is shown behind the visibile tasks
private AppWindowToken mHomeAppToken;
@@ -98,17 +100,13 @@ public class RecentsAnimationController {
final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
final Task task = adapter.mTask;
if (task.mTaskId == taskId) {
- // TODO: Save this screenshot as the task snapshot?
- final Rect taskFrame = new Rect();
- task.getBounds(taskFrame);
- final GraphicBuffer buffer = SurfaceControl.captureLayers(
- task.getSurfaceControl().getHandle(), taskFrame, 1f);
- final AppWindowToken topChild = task.getTopChild();
- final WindowState mainWindow = topChild.findMainWindow();
- return new TaskSnapshot(buffer, topChild.getConfiguration().orientation,
- mainWindow.mContentInsets,
- ActivityManager.isLowRamDeviceStatic() /* reduced */,
- 1.0f /* scale */);
+ final TaskSnapshotController snapshotController =
+ mService.mTaskSnapshotController;
+ final ArraySet<Task> tasks = Sets.newArraySet(task);
+ snapshotController.snapshotTasks(tasks);
+ snapshotController.addSkipClosingAppSnapshotTasks(tasks);
+ return snapshotController.getSnapshot(taskId, 0 /* userId */,
+ false /* restoreFromDisk */, false /* reducedResolution */);
}
}
return null;
@@ -159,8 +157,6 @@ public class RecentsAnimationController {
};
/**
- * Initializes a new RecentsAnimationController.
- *
* @param remoteAnimationRunner The remote runner which should be notified when the animation is
* ready to start or has been canceled
* @param callbacks Callbacks to be made when the animation finishes
@@ -171,16 +167,19 @@ public class RecentsAnimationController {
mService = service;
mRunner = remoteAnimationRunner;
mCallbacks = callbacks;
+ mDisplayId = displayId;
+ }
- final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
- final ArrayList<Task> visibleTasks = dc.getVisibleTasks();
- if (visibleTasks.isEmpty()) {
- cancelAnimation();
- return;
- }
-
+ /**
+ * Initializes the recents animation controller. This is a separate call from the constructor
+ * because it may call cancelAnimation() which needs to properly clean up the controller
+ * in the window manager.
+ */
+ public void initialize() {
// Make leashes for each of the visible tasks and add it to the recents animation to be
// started
+ final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
+ final ArrayList<Task> visibleTasks = dc.getVisibleTasks();
final int taskCount = visibleTasks.size();
for (int i = 0; i < taskCount; i++) {
final Task task = visibleTasks.get(i);
@@ -193,6 +192,12 @@ public class RecentsAnimationController {
addAnimation(task);
}
+ // Skip the animation if there is nothing to animate
+ if (mPendingAnimations.isEmpty()) {
+ cancelAnimation();
+ return;
+ }
+
// Adjust the wallpaper visibility for the showing home activity
final AppWindowToken recentsComponentAppToken =
dc.getHomeStack().getTopChild().getTopFullscreenAppToken();
@@ -222,8 +227,10 @@ public class RecentsAnimationController {
}
void startAnimation() {
- if (DEBUG) Log.d(TAG, "startAnimation(): mPendingStart=" + mPendingStart);
- if (!mPendingStart) {
+ if (DEBUG) Log.d(TAG, "startAnimation(): mPendingStart=" + mPendingStart
+ + " mCanceled=" + mCanceled);
+ if (!mPendingStart || mCanceled) {
+ // Skip starting if we've already started or canceled the animation
return;
}
try {
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index c353c1d36d60..35fc99fe4612 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -34,6 +34,7 @@ import android.view.SurfaceControl.Transaction;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
/**
@@ -48,13 +49,7 @@ class RemoteAnimationController {
private final ArrayList<RemoteAnimationAdapterWrapper> mPendingAnimations = new ArrayList<>();
private final Rect mTmpRect = new Rect();
private final Handler mHandler;
-
- private final IRemoteAnimationFinishedCallback mFinishedCallback = new Stub() {
- @Override
- public void onAnimationFinished() throws RemoteException {
- RemoteAnimationController.this.onAnimationFinished();
- }
- };
+ private FinishedCallback mFinishedCallback;
private final Runnable mTimeoutRunnable = () -> {
onAnimationFinished();
@@ -96,13 +91,18 @@ class RemoteAnimationController {
// Scale the timeout with the animator scale the controlling app is using.
mHandler.postDelayed(mTimeoutRunnable,
(long) (TIMEOUT_MS * mService.getCurrentAnimatorScale()));
- try {
- mRemoteAnimationAdapter.getRunner().onAnimationStart(createAnimations(),
- mFinishedCallback);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to start remote animation", e);
- onAnimationFinished();
- }
+ mFinishedCallback = new FinishedCallback(this);
+
+ final RemoteAnimationTarget[] animations = createAnimations();
+ mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
+ try {
+ mRemoteAnimationAdapter.getRunner().onAnimationStart(animations,
+ mFinishedCallback);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to start remote animation", e);
+ onAnimationFinished();
+ }
+ });
}
private RemoteAnimationTarget[] createAnimations() {
@@ -120,6 +120,7 @@ class RemoteAnimationController {
private void onAnimationFinished() {
mHandler.removeCallbacks(mTimeoutRunnable);
synchronized (mService.mWindowMap) {
+ releaseFinishedCallback();
mService.openSurfaceTransaction();
try {
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
@@ -140,6 +141,41 @@ class RemoteAnimationController {
}
}
+ private void releaseFinishedCallback() {
+ if (mFinishedCallback != null) {
+ mFinishedCallback.release();
+ mFinishedCallback = null;
+ }
+ }
+
+ private static final class FinishedCallback extends IRemoteAnimationFinishedCallback.Stub {
+
+ RemoteAnimationController mOuter;
+
+ FinishedCallback(RemoteAnimationController outer) {
+ mOuter = outer;
+ }
+
+ @Override
+ public void onAnimationFinished() throws RemoteException {
+ if (mOuter != null) {
+ mOuter.onAnimationFinished();
+
+ // In case the client holds on to the finish callback, make sure we don't leak
+ // RemoteAnimationController which in turn would leak the runner on the client.
+ mOuter = null;
+ }
+ }
+
+ /**
+ * Marks this callback as not be used anymore by releasing the reference to the outer class
+ * to prevent memory leak.
+ */
+ void release() {
+ mOuter = null;
+ }
+ };
+
private class RemoteAnimationAdapterWrapper implements AnimationAdapter {
private final AppWindowToken mAppWindowToken;
@@ -208,6 +244,7 @@ class RemoteAnimationController {
mPendingAnimations.remove(this);
if (mPendingAnimations.isEmpty()) {
mHandler.removeCallbacks(mTimeoutRunnable);
+ releaseFinishedCallback();
invokeAnimationCancelled();
}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index f5760e593f37..3d60ee4b5e1e 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -588,6 +588,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
"<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
}
+ mService.mAnimator.executeAfterPrepareSurfacesRunnables();
+
final WindowSurfacePlacer surfacePlacer = mService.mWindowPlacerLocked;
// If we are ready to perform an app transition, check through all of the app tokens to be
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index a7a2b534131d..3d7b32ca1a9d 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -92,6 +92,7 @@ class TaskSnapshotController {
private final TaskSnapshotPersister mPersister = new TaskSnapshotPersister(
Environment::getDataSystemCeDirectory);
private final TaskSnapshotLoader mLoader = new TaskSnapshotLoader(mPersister);
+ private final ArraySet<Task> mSkipClosingAppSnapshotTasks = new ArraySet<>();
private final ArraySet<Task> mTmpTasks = new ArraySet<>();
private final Handler mHandler = new Handler();
@@ -149,10 +150,20 @@ class TaskSnapshotController {
// either closing or hidden.
getClosingTasks(closingApps, mTmpTasks);
snapshotTasks(mTmpTasks);
+ mSkipClosingAppSnapshotTasks.clear();
+ }
+ /**
+ * Adds the given {@param tasks} to the list of tasks which should not have their snapshots
+ * taken upon the next processing of the set of closing apps. The caller is responsible for
+ * calling {@link #snapshotTasks} to ensure that the task has an up-to-date snapshot.
+ */
+ @VisibleForTesting
+ void addSkipClosingAppSnapshotTasks(ArraySet<Task> tasks) {
+ mSkipClosingAppSnapshotTasks.addAll(tasks);
}
- private void snapshotTasks(ArraySet<Task> tasks) {
+ void snapshotTasks(ArraySet<Task> tasks) {
for (int i = tasks.size() - 1; i >= 0; i--) {
final Task task = tasks.valueAt(i);
final int mode = getSnapshotMode(task);
@@ -295,7 +306,7 @@ class TaskSnapshotController {
// If the task of the app is not visible anymore, it means no other app in that task
// is opening. Thus, the task is closing.
- if (task != null && !task.isVisible()) {
+ if (task != null && !task.isVisible() && !mSkipClosingAppSnapshotTasks.contains(task)) {
outClosingTasks.add(task);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 49a30d5382c3..20349b990dfe 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -92,6 +92,7 @@ public class WindowAnimator {
* executed and the corresponding transaction is closed and applied.
*/
private final ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>();
+ private boolean mInExecuteAfterPrepareSurfacesRunnables;
WindowAnimator(final WindowManagerService service) {
mService = service;
@@ -434,11 +435,24 @@ public class WindowAnimator {
* the corresponding transaction is closed and applied.
*/
void addAfterPrepareSurfacesRunnable(Runnable r) {
+ // If runnables are already being handled in executeAfterPrepareSurfacesRunnable, then just
+ // immediately execute the runnable passed in.
+ if (mInExecuteAfterPrepareSurfacesRunnables) {
+ r.run();
+ return;
+ }
+
mAfterPrepareSurfacesRunnables.add(r);
scheduleAnimation();
}
- private void executeAfterPrepareSurfacesRunnables() {
+ void executeAfterPrepareSurfacesRunnables() {
+
+ // Don't even think about to start recursing!
+ if (mInExecuteAfterPrepareSurfacesRunnables) {
+ return;
+ }
+ mInExecuteAfterPrepareSurfacesRunnables = true;
// Traverse in order they were added.
final int size = mAfterPrepareSurfacesRunnables.size();
@@ -446,5 +460,6 @@ public class WindowAnimator {
mAfterPrepareSurfacesRunnables.get(i).run();
}
mAfterPrepareSurfacesRunnables.clear();
+ mInExecuteAfterPrepareSurfacesRunnables = false;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 6bd7f22a4a4c..1f7caffd1916 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1142,7 +1142,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
scheduleAnimation();
}
- private void reassignLayer(Transaction t) {
+ void reassignLayer(Transaction t) {
final WindowContainer parent = getParent();
if (parent != null) {
parent.assignChildLayers(t);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c2ed2ae30227..966f6226caed 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2680,6 +2680,7 @@ public class WindowManagerService extends IWindowManager.Stub
cancelRecentsAnimation();
mRecentsAnimationController = new RecentsAnimationController(this,
recentsAnimationRunner, callbacks, displayId);
+ mRecentsAnimationController.initialize();
}
}
@@ -2687,6 +2688,19 @@ public class WindowManagerService extends IWindowManager.Stub
return mRecentsAnimationController;
}
+ /**
+ * @return Whether the next recents animation can continue to start. Called from
+ * {@link RecentsAnimation#startRecentsActivity}.
+ */
+ public boolean canStartRecentsAnimation() {
+ synchronized (mWindowMap) {
+ if (mAppTransition.isTransitionSet()) {
+ return false;
+ }
+ return true;
+ }
+ }
+
public void cancelRecentsAnimation() {
synchronized (mWindowMap) {
if (mRecentsAnimationController != null) {
@@ -2991,7 +3005,9 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void dismissKeyguard(IKeyguardDismissCallback callback, CharSequence message) {
- checkCallingPermission(permission.CONTROL_KEYGUARD, "dismissKeyguard");
+ if (!checkCallingPermission(permission.CONTROL_KEYGUARD, "dismissKeyguard")) {
+ throw new SecurityException("Requires CONTROL_KEYGUARD permission");
+ }
synchronized(mWindowMap) {
mPolicy.dismissKeyguardLw(callback, message);
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 72f95fb74f4f..0b032815f1fe 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -41,6 +41,7 @@ cc_library_static {
"com_android_server_tv_TvUinputBridge.cpp",
"com_android_server_tv_TvInputHal.cpp",
"com_android_server_vr_VrManagerService.cpp",
+ "com_android_server_UsbAlsaJackDetector.cpp",
"com_android_server_UsbDeviceManager.cpp",
"com_android_server_UsbDescriptorParser.cpp",
"com_android_server_UsbMidiDevice.cpp",
@@ -97,6 +98,7 @@ cc_defaults {
"libgui",
"libusbhost",
"libsuspend",
+ "libtinyalsa",
"libEGL",
"libGLESv2",
"libnetutils",
diff --git a/services/core/jni/com_android_server_UsbAlsaJackDetector.cpp b/services/core/jni/com_android_server_UsbAlsaJackDetector.cpp
new file mode 100644
index 000000000000..e9d448234e17
--- /dev/null
+++ b/services/core/jni/com_android_server_UsbAlsaJackDetector.cpp
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "UsbAlsaJackDetectorJNI"
+#include "utils/Log.h"
+
+#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <asm/byteorder.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <tinyalsa/asoundlib.h>
+
+#define DRIVER_NAME "/dev/usb_accessory"
+
+#define USB_IN_JACK_NAME "USB in Jack"
+#define USB_OUT_JACK_NAME "USB out Jack"
+
+namespace android
+{
+
+static jboolean is_jack_connected(jint card, const char* control) {
+ struct mixer* card_mixer = mixer_open(card);
+ if (card_mixer == NULL) {
+ return true;
+ }
+ struct mixer_ctl* ctl = mixer_get_ctl_by_name(card_mixer, control);
+ if (!ctl) {
+ return true;
+ }
+ mixer_ctl_update(ctl);
+ int val = mixer_ctl_get_value(ctl, 0);
+ ALOGI("JACK %s - value %d\n", control, val);
+ mixer_close(card_mixer);
+
+ return val != 0;
+}
+
+static jboolean android_server_UsbAlsaJackDetector_hasJackDetect(JNIEnv* /* env */,
+ jobject /* thiz */,
+ jint card)
+{
+ struct mixer* card_mixer = mixer_open(card);
+ if (card_mixer == NULL) {
+ return false;
+ }
+
+ jboolean has_jack = false;
+ if ((mixer_get_ctl_by_name(card_mixer, USB_IN_JACK_NAME) != NULL) ||
+ (mixer_get_ctl_by_name(card_mixer, USB_OUT_JACK_NAME) != NULL)) {
+ has_jack = true;
+ }
+ mixer_close(card_mixer);
+ return has_jack;
+}
+
+
+static jboolean android_server_UsbAlsaJackDetector_inputJackConnected(JNIEnv* /* env */,
+ jobject /* thiz */,
+ jint card)
+{
+ return is_jack_connected(card, USB_IN_JACK_NAME);
+}
+
+
+static jboolean android_server_UsbAlsaJackDetector_outputJackConnected(JNIEnv* /* env */,
+ jobject /* thiz */,
+ jint card)
+{
+ return is_jack_connected(card, USB_OUT_JACK_NAME);
+}
+
+static void android_server_UsbAlsaJackDetector_jackDetect(JNIEnv* env,
+ jobject thiz,
+ jint card) {
+ jclass jdclass = env->GetObjectClass(thiz);
+ jmethodID method_jackDetectCallback = env->GetMethodID(jdclass, "jackDetectCallback", "()Z");
+ if (method_jackDetectCallback == NULL) {
+ ALOGE("Can't find jackDetectCallback");
+ return;
+ }
+
+ struct mixer* m = mixer_open(card);
+ if (!m) {
+ ALOGE("Jack detect unable to open mixer\n");
+ return;
+ }
+ mixer_subscribe_events(m, 1);
+ do {
+
+ // Wait for a mixer event. Retry if interrupted, exit on error.
+ int retval;
+ do {
+ retval = mixer_wait_event(m, -1);
+ } while (retval == -EINTR);
+ if (retval < 0) {
+ break;
+ }
+ mixer_consume_event(m);
+ } while (env->CallBooleanMethod(thiz, method_jackDetectCallback));
+
+ mixer_close(m);
+ return;
+}
+
+static const JNINativeMethod method_table[] = {
+ { "nativeHasJackDetect", "(I)Z", (void*)android_server_UsbAlsaJackDetector_hasJackDetect },
+ { "nativeInputJackConnected", "(I)Z",
+ (void*)android_server_UsbAlsaJackDetector_inputJackConnected },
+ { "nativeOutputJackConnected", "(I)Z",
+ (void*)android_server_UsbAlsaJackDetector_outputJackConnected },
+ { "nativeJackDetect", "(I)Z", (void*)android_server_UsbAlsaJackDetector_jackDetect },
+};
+
+int register_android_server_UsbAlsaJackDetector(JNIEnv *env)
+{
+ jclass clazz = env->FindClass("com/android/server/usb/UsbAlsaJackDetector");
+ if (clazz == NULL) {
+ ALOGE("Can't find com/android/server/usb/UsbAlsaJackDetector");
+ return -1;
+ }
+
+ if (!jniRegisterNativeMethods(env, "com/android/server/usb/UsbAlsaJackDetector",
+ method_table, NELEM(method_table))) {
+ ALOGE("Can't register UsbAlsaJackDetector native methods");
+ return -1;
+ }
+
+ return 0;
+}
+
+}
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 8fd5be2a45ff..c2771e4b931f 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -51,6 +51,7 @@ static jmethodID method_setGnssYearOfHardware;
static jmethodID method_setGnssHardwareModelName;
static jmethodID method_xtraDownloadRequest;
static jmethodID method_reportNiNotification;
+static jmethodID method_requestLocation;
static jmethodID method_requestRefLocation;
static jmethodID method_requestSetID;
static jmethodID method_requestUtcTime;
@@ -346,6 +347,34 @@ static jobject translateLocation(JNIEnv* env, const GnssLocation& location) {
return object.get();
}
+static GnssLocation createGnssLocation(
+ jint gnssLocationFlags,
+ jdouble latitudeDegrees,
+ jdouble longitudeDegrees,
+ jdouble altitudeMeters,
+ jfloat speedMetersPerSec,
+ jfloat bearingDegrees,
+ jfloat horizontalAccuracyMeters,
+ jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond,
+ jfloat bearingAccuracyDegrees,
+ jlong timestamp) {
+ GnssLocation location;
+ location.gnssLocationFlags = static_cast<uint16_t>(gnssLocationFlags);
+ location.latitudeDegrees = static_cast<double>(latitudeDegrees);
+ location.longitudeDegrees = static_cast<double>(longitudeDegrees);
+ location.altitudeMeters = static_cast<double>(altitudeMeters);
+ location.speedMetersPerSec = static_cast<float>(speedMetersPerSec);
+ location.bearingDegrees = static_cast<float>(bearingDegrees);
+ location.horizontalAccuracyMeters = static_cast<float>(horizontalAccuracyMeters);
+ location.verticalAccuracyMeters = static_cast<float>(verticalAccuracyMeters);
+ location.speedAccuracyMetersPerSecond = static_cast<float>(speedAccuracyMetersPerSecond);
+ location.bearingAccuracyDegrees = static_cast<float>(bearingAccuracyDegrees);
+ location.timestamp = static_cast<uint64_t>(timestamp);
+
+ return location;
+}
+
/*
* GnssCallback class implements the callback methods for IGnss interface.
*/
@@ -474,7 +503,9 @@ Return<void> GnssCallback::gnssRequestTimeCb() {
}
Return<void> GnssCallback::gnssRequestLocationCb(const bool independentFromGnss) {
- // TODO(b/72405645): call into java implementation
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_requestLocation, boolToJbool(independentFromGnss));
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
return Void();
}
@@ -1042,6 +1073,7 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env,
method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
"(IIIIILjava/lang/String;Ljava/lang/String;II)V");
+ method_requestLocation = env->GetMethodID(clazz, "requestLocation", "(Z)V");
method_requestRefLocation = env->GetMethodID(clazz, "requestRefLocation", "()V");
method_requestSetID = env->GetMethodID(clazz, "requestSetID", "(I)V");
method_requestUtcTime = env->GetMethodID(clazz, "requestUtcTime", "()V");
@@ -1441,6 +1473,42 @@ static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */,
}
}
+static void android_location_GnssLocationProvider_inject_best_location(
+ JNIEnv*,
+ jobject,
+ jint gnssLocationFlags,
+ jdouble latitudeDegrees,
+ jdouble longitudeDegrees,
+ jdouble altitudeMeters,
+ jfloat speedMetersPerSec,
+ jfloat bearingDegrees,
+ jfloat horizontalAccuracyMeters,
+ jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond,
+ jfloat bearingAccuracyDegrees,
+ jlong timestamp) {
+ if (gnssHal_V1_1 != nullptr) {
+ GnssLocation location = createGnssLocation(
+ gnssLocationFlags,
+ latitudeDegrees,
+ longitudeDegrees,
+ altitudeMeters,
+ speedMetersPerSec,
+ bearingDegrees,
+ horizontalAccuracyMeters,
+ verticalAccuracyMeters,
+ speedAccuracyMetersPerSecond,
+ bearingAccuracyDegrees,
+ timestamp);
+ auto result = gnssHal_V1_1->injectBestLocation(location);
+ if (!result.isOk() || !result) {
+ ALOGE("%s: Gnss injectBestLocation() failed.", __func__);
+ }
+ } else {
+ ALOGE("%s: injectBestLocation() is called but gnssHal_V1_1 is not available.", __func__);
+ }
+}
+
static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env */,
jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy) {
if (gnssHal != nullptr) {
@@ -1996,6 +2064,9 @@ static const JNINativeMethod sMethods[] = {
android_location_GnssLocationProvider_read_nmea)},
{"native_inject_time", "(JJI)V", reinterpret_cast<void *>(
android_location_GnssLocationProvider_inject_time)},
+ {"native_inject_best_location",
+ "(IDDDFFFFFFJ)V",
+ reinterpret_cast<void *>(android_location_GnssLocationProvider_inject_best_location)},
{"native_inject_location",
"(DDF)V",
reinterpret_cast<void *>(android_location_GnssLocationProvider_inject_location)},
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index bf2a637cf54e..0ebef37c1f2f 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -34,6 +34,7 @@ int register_android_server_PowerManagerService(JNIEnv* env);
int register_android_server_storage_AppFuse(JNIEnv* env);
int register_android_server_SerialService(JNIEnv* env);
int register_android_server_SystemServer(JNIEnv* env);
+int register_android_server_UsbAlsaJackDetector(JNIEnv* env);
int register_android_server_UsbDeviceManager(JNIEnv* env);
int register_android_server_UsbMidiDevice(JNIEnv* env);
int register_android_server_UsbHostManager(JNIEnv* env);
@@ -82,6 +83,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_android_server_AlarmManagerService(env);
register_android_server_UsbDeviceManager(env);
register_android_server_UsbMidiDevice(env);
+ register_android_server_UsbAlsaJackDetector(env);
register_android_server_UsbHostManager(env);
register_android_server_vr_VrManagerService(env);
register_android_server_VibratorService(env);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 75bb5e4f8a6b..61c8b79ae3ce 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -196,7 +196,7 @@ public final class SystemServer {
private static final String THERMAL_OBSERVER_CLASS =
"com.google.android.clockwork.ThermalObserver";
private static final String WEAR_CONNECTIVITY_SERVICE_CLASS =
- "com.google.android.clockwork.connectivity.WearConnectivityService";
+ "com.android.clockwork.connectivity.WearConnectivityService";
private static final String WEAR_SIDEKICK_SERVICE_CLASS =
"com.google.android.clockwork.sidekick.SidekickService";
private static final String WEAR_DISPLAY_SERVICE_CLASS =
diff --git a/services/robotests/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
index 44ac8039bbed..503adb29471c 100644
--- a/services/robotests/src/com/android/server/backup/TransportManagerTest.java
+++ b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
@@ -19,14 +19,12 @@ package com.android.server.backup;
import static com.android.server.backup.testing.TransportData.genericTransport;
import static com.android.server.backup.testing.TransportTestUtils.mockTransport;
import static com.android.server.backup.testing.TransportTestUtils.setUpTransportsForTransportManager;
+
import static com.google.common.truth.Truth.assertThat;
-import static java.util.Arrays.asList;
-import static java.util.Collections.emptyList;
-import static java.util.Collections.singletonList;
-import static java.util.stream.Collectors.toList;
-import static java.util.stream.Collectors.toSet;
-import static java.util.stream.Stream.concat;
+
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -35,6 +33,13 @@ import static org.mockito.Mockito.when;
import static org.robolectric.shadow.api.Shadow.extract;
import static org.testng.Assert.expectThrows;
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toSet;
+import static java.util.stream.Stream.concat;
+
import android.annotation.Nullable;
import android.app.backup.BackupManager;
import android.content.ComponentName;
@@ -43,6 +48,7 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.platform.test.annotations.Presubmit;
+
import com.android.server.backup.testing.ShadowContextImplForBackup;
import com.android.server.backup.testing.TransportData;
import com.android.server.backup.testing.TransportTestUtils.TransportMock;
@@ -54,11 +60,7 @@ import com.android.server.testing.FrameworkRobolectricTestRunner;
import com.android.server.testing.SystemLoaderPackages;
import com.android.server.testing.shadows.FrameworkShadowContextImpl;
import com.android.server.testing.shadows.FrameworkShadowPackageManager;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.stream.Stream;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -69,6 +71,12 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowPackageManager;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Stream;
+
@RunWith(FrameworkRobolectricTestRunner.class)
@Config(
manifest = Config.NONE,
@@ -81,6 +89,12 @@ public class TransportManagerTest {
private static final String PACKAGE_A = "some.package.a";
private static final String PACKAGE_B = "some.package.b";
+ /**
+ * GMSCore depends on this constant so we define it here on top of the definition in
+ * {@link TransportManager} to verify this extra is passed
+ */
+ private static final String EXTRA_TRANSPORT_REGISTRATION = "transport_registration";
+
@Mock private OnTransportRegisteredListener mListener;
@Mock private TransportClientManager mTransportClientManager;
private TransportData mTransportA1;
@@ -195,6 +209,22 @@ public class TransportManagerTest {
}
@Test
+ public void testRegisterTransports_passesRegistrationExtraToGetTransportClient()
+ throws Exception {
+ setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+ setUpTransports(mTransportA1);
+ TransportManager transportManager = createTransportManager(mTransportA1);
+
+ transportManager.registerTransports();
+
+ verify(mTransportClientManager)
+ .getTransportClient(
+ eq(mTransportA1.getTransportComponent()),
+ argThat(bundle -> bundle.getBoolean(EXTRA_TRANSPORT_REGISTRATION)),
+ anyString());
+ }
+
+ @Test
public void testOnPackageAdded_registerTransports() throws Exception {
setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
setUpTransports(mTransportA1);
@@ -580,6 +610,9 @@ public class TransportManagerTest {
when(mTransportClientManager.getTransportClient(
eq(transport.getTransportComponent()), any()))
.thenReturn(transportMock.transportClient);
+ when(mTransportClientManager.getTransportClient(
+ eq(transport.getTransportComponent()), any(), any()))
+ .thenReturn(transportMock.transportClient);
transportMocks.add(transportMock);
}
return transportMocks;
diff --git a/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java b/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java
new file mode 100644
index 000000000000..5e3c9741ae70
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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
+ */
+
+package com.android.server.backup.transport;
+
+import static com.android.server.backup.TransportManager.SERVICE_ACTION_TRANSPORT_HOST;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.argThat;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderPackages;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+@RunWith(FrameworkRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, sdk = 26)
+@SystemLoaderPackages({"com.android.server.backup"})
+@Presubmit
+public class TransportClientManagerTest {
+
+ private static final String PACKAGE_NAME = "random.package.name";
+ private static final String CLASS_NAME = "random.package.name.transport.Transport";
+
+ @Mock private Context mContext;
+ @Mock private TransportConnectionListener mTransportConnectionListener;
+ private TransportClientManager mTransportClientManager;
+ private ComponentName mTransportComponent;
+ private Intent mBindIntent;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mTransportClientManager = new TransportClientManager(mContext);
+ mTransportComponent = new ComponentName(PACKAGE_NAME, CLASS_NAME);
+ mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(mTransportComponent);
+
+ when(mContext.bindServiceAsUser(
+ any(Intent.class),
+ any(ServiceConnection.class),
+ anyInt(),
+ any(UserHandle.class)))
+ .thenReturn(true);
+ }
+
+ @Test
+ public void testGetTransportClient_withExtras_createsTransportClientWithCorrectIntent() {
+ Bundle extras = new Bundle();
+ extras.putBoolean("random_extra", true);
+ mBindIntent.putExtras(extras);
+
+ TransportClient transportClient =
+ mTransportClientManager.getTransportClient(mTransportComponent, extras, "caller");
+
+ transportClient.connectAsync(mTransportConnectionListener, "caller");
+ verify(mContext)
+ .bindServiceAsUser(
+ argThat(matchesIntentAndExtras(mBindIntent)),
+ any(ServiceConnection.class),
+ anyInt(),
+ any(UserHandle.class));
+ }
+
+ private ArgumentMatcher<Intent> matchesIntentAndExtras(Intent expectedIntent) {
+ return (Intent actualIntent) -> {
+ if (!expectedIntent.filterEquals(actualIntent)) {
+ return false;
+ }
+
+ Bundle expectedExtras = expectedIntent.getExtras();
+ Bundle actualExtras = actualIntent.getExtras();
+
+ if (expectedExtras == null && actualExtras == null) {
+ return true;
+ }
+
+ if (expectedExtras == null || actualExtras == null) {
+ return false;
+ }
+
+ if (expectedExtras.size() != actualExtras.size()) {
+ return false;
+ }
+
+ for (String key : expectedExtras.keySet()) {
+ if (!expectedExtras.get(key).equals(actualExtras.get(key))) {
+ return false;
+ }
+ }
+
+ return true;
+ };
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 184e8de15973..e1b4422c83c4 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -104,6 +104,7 @@ import android.os.PersistableBundle;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.RemoteException;
+import android.os.SimpleClock;
import android.os.UserHandle;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
@@ -118,7 +119,6 @@ import android.util.DataUnit;
import android.util.Log;
import android.util.Pair;
import android.util.RecurrenceRule;
-import android.util.TrustedTime;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.util.test.BroadcastInterceptingContext;
@@ -158,6 +158,7 @@ import java.time.Clock;
import java.time.Instant;
import java.time.Period;
import java.time.ZoneId;
+import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.Calendar;
@@ -215,7 +216,6 @@ public class NetworkPolicyManagerServiceTest {
private @Mock IActivityManager mActivityManager;
private @Mock INetworkStatsService mStatsService;
private @Mock INetworkManagementService mNetworkManager;
- private @Mock TrustedTime mTime;
private @Mock IConnectivityManager mConnManager;
private @Mock NotificationManager mNotifManager;
private @Mock PackageManager mPackageManager;
@@ -267,6 +267,13 @@ public class NetworkPolicyManagerServiceTest {
public final @Rule NetPolicyMethodRule mNetPolicyXmlRule = new NetPolicyMethodRule();
+ private final Clock mClock = new SimpleClock(ZoneOffset.UTC) {
+ @Override
+ public long millis() {
+ return currentTimeMillis();
+ }
+ };
+
private void registerLocalServices() {
addLocalServiceMock(DeviceIdleController.LocalService.class);
@@ -341,7 +348,7 @@ public class NetworkPolicyManagerServiceTest {
mFutureIntent = newRestrictBackgroundChangedFuture();
mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, mStatsService,
- mNetworkManager, mIpm, mTime, mPolicyDir, true);
+ mNetworkManager, mIpm, mClock, mPolicyDir, true);
mService.bindConnectivityManager(mConnManager);
mPolicyListener = new NetworkPolicyListenerAnswer(mService);
@@ -370,7 +377,6 @@ public class NetworkPolicyManagerServiceTest {
when(mPackageManager.getPackagesForUid(UID_A)).thenReturn(new String[] {PKG_NAME_A});
when(mNetworkManager.isBandwidthControlEnabled()).thenReturn(true);
when(mNetworkManager.setDataSaverModeEnabled(anyBoolean())).thenReturn(true);
- expectCurrentTime();
// Prepare NPMS.
mService.systemReady(mService.networkScoreAndNetworkManagementServiceReady());
@@ -940,7 +946,6 @@ public class NetworkPolicyManagerServiceTest {
// which means we shouldn't push limit to interface.
state = new NetworkState[] { buildWifi() };
when(mConnManager.getAllNetworkState()).thenReturn(state);
- expectCurrentTime();
mPolicyListener.expect().onMeteredIfacesChanged(any());
mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
@@ -949,7 +954,6 @@ public class NetworkPolicyManagerServiceTest {
// now change cycle to be on 15th, and test in early march, to verify we
// pick cycle day in previous month.
when(mConnManager.getAllNetworkState()).thenReturn(state);
- expectCurrentTime();
// pretend that 512 bytes total have happened
stats = new NetworkStats(getElapsedRealtime(), 1)
@@ -996,7 +1000,6 @@ public class NetworkPolicyManagerServiceTest {
final long start = parseTime("2015-11-01T00:00Z");
final long end = parseTime("2015-11-07T00:00Z");
setCurrentTimeMillis(end);
- expectCurrentTime();
// Normal usage means no notification
{
@@ -1096,7 +1099,6 @@ public class NetworkPolicyManagerServiceTest {
final long start = parseTime("2015-11-01T00:00Z");
final long end = parseTime("2015-11-07T00:00Z");
setCurrentTimeMillis(end);
- expectCurrentTime();
// Using 20% data in 20% time is normal
{
@@ -1139,7 +1141,6 @@ public class NetworkPolicyManagerServiceTest {
.addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L);
{
- expectCurrentTime();
when(mConnManager.getAllNetworkState()).thenReturn(state);
when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
currentTimeMillis())).thenReturn(stats.getTotalBytes());
@@ -1474,14 +1475,6 @@ public class NetworkPolicyManagerServiceTest {
return new NetworkState(info, prop, networkCapabilities, null, null, TEST_SSID);
}
- private void expectCurrentTime() throws Exception {
- when(mTime.forceRefresh()).thenReturn(false);
- when(mTime.hasCache()).thenReturn(true);
- when(mTime.currentTimeMillis()).thenReturn(currentTimeMillis());
- when(mTime.getCacheAge()).thenReturn(0L);
- when(mTime.getCacheCertainty()).thenReturn(0L);
- }
-
private void expectHasInternetPermission(int uid, boolean hasIt) throws Exception {
when(mIpm.checkUidPermission(Manifest.permission.INTERNET, uid)).thenReturn(
hasIt ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
index 07262e17c752..23fe0ffda60e 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
@@ -34,7 +34,6 @@ import static org.mockito.Mockito.verify;
import android.annotation.NonNull;
import android.content.Context;
-import android.os.Handler;
import android.os.Message;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
@@ -49,9 +48,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.concurrent.CompletableFuture;
import java.util.function.IntConsumer;
-import java.util.function.Supplier;
/**
@@ -283,6 +280,19 @@ public class MagnificationGestureHandlerTest {
verify(mMgh.getNext(), times(2)).onMotionEvent(any(), any(), anyInt());
}
+ @Test
+ public void testTripleTapAndHold_zoomsImmediately() {
+ assertZoomsImmediatelyOnSwipeFrom(STATE_2TAPS);
+ assertZoomsImmediatelyOnSwipeFrom(STATE_SHORTCUT_TRIGGERED);
+ }
+
+ private void assertZoomsImmediatelyOnSwipeFrom(int state) {
+ goFromStateIdleTo(state);
+ swipeAndHold();
+ assertIn(STATE_DRAGGING_TMP);
+ returnToNormalFrom(STATE_DRAGGING_TMP);
+ }
+
private void assertTransition(int fromState, Runnable transitionAction, int toState) {
goFromStateIdleTo(fromState);
transitionAction.run();
@@ -339,11 +349,13 @@ public class MagnificationGestureHandlerTest {
check(tapCount() == 2, state);
} break;
case STATE_DRAGGING: {
+ check(isZoomed(), state);
check(mMgh.mCurrentState == mMgh.mViewportDraggingState,
state);
check(mMgh.mViewportDraggingState.mZoomedInBeforeDrag, state);
} break;
case STATE_DRAGGING_TMP: {
+ check(isZoomed(), state);
check(mMgh.mCurrentState == mMgh.mViewportDraggingState,
state);
check(!mMgh.mViewportDraggingState.mZoomedInBeforeDrag, state);
@@ -353,11 +365,13 @@ public class MagnificationGestureHandlerTest {
check(!isZoomed(), state);
} break;
case STATE_PANNING: {
+ check(isZoomed(), state);
check(mMgh.mCurrentState == mMgh.mPanningScalingState,
state);
check(!mMgh.mPanningScalingState.mScaling, state);
} break;
case STATE_SCALING_AND_PANNING: {
+ check(isZoomed(), state);
check(mMgh.mCurrentState == mMgh.mPanningScalingState,
state);
check(mMgh.mPanningScalingState.mScaling, state);
diff --git a/services/tests/servicestests/src/com/android/server/am/PendingRemoteAnimationRegistryTest.java b/services/tests/servicestests/src/com/android/server/am/PendingRemoteAnimationRegistryTest.java
new file mode 100644
index 000000000000..2baf9952cb9e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/PendingRemoteAnimationRegistryTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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
+ */
+
+package com.android.server.am;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.annotation.Nullable;
+import android.app.ActivityOptions;
+import android.os.Handler;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.FlakyTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.ArrayMap;
+import android.view.RemoteAnimationAdapter;
+
+import com.android.server.testutils.OffsettableClock;
+import com.android.server.testutils.TestHandler;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * atest PendingRemoteAnimationRegistryTest
+ */
+@SmallTest
+@Presubmit
+@FlakyTest
+@RunWith(AndroidJUnit4.class)
+public class PendingRemoteAnimationRegistryTest extends ActivityTestsBase {
+
+ @Mock RemoteAnimationAdapter mAdapter;
+ private PendingRemoteAnimationRegistry mRegistry;
+ private final OffsettableClock mClock = new OffsettableClock.Stopped();
+ private TestHandler mHandler;
+ private ActivityManagerService mService;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ MockitoAnnotations.initMocks(this);
+ mService = createActivityManagerService();
+ mService.mHandlerThread.getThreadHandler().runWithScissors(() -> {
+ mHandler = new TestHandler(null, mClock);
+ }, 0);
+ mRegistry = new PendingRemoteAnimationRegistry(mService, mHandler);
+ }
+
+ @Test
+ public void testOverrideActivityOptions() {
+ mRegistry.addPendingAnimation("com.android.test", mAdapter);
+ ActivityOptions opts = ActivityOptions.makeBasic();
+ opts = mRegistry.overrideOptionsIfNeeded("com.android.test", opts);
+ assertEquals(mAdapter, opts.getRemoteAnimationAdapter());
+ }
+
+ @Test
+ public void testOverrideActivityOptions_null() {
+ mRegistry.addPendingAnimation("com.android.test", mAdapter);
+ final ActivityOptions opts = mRegistry.overrideOptionsIfNeeded("com.android.test", null);
+ assertNotNull(opts);
+ assertEquals(mAdapter, opts.getRemoteAnimationAdapter());
+ }
+
+ @Test
+ public void testTimeout() {
+ mRegistry.addPendingAnimation("com.android.test", mAdapter);
+ mClock.fastForward(5000);
+ mHandler.timeAdvance();
+ assertNull(mRegistry.overrideOptionsIfNeeded("com.android.test", null));
+ }
+
+ @Test
+ public void testTimeout_overridenEntry() {
+ mRegistry.addPendingAnimation("com.android.test", mAdapter);
+ mClock.fastForward(2500);
+ mHandler.timeAdvance();
+ mRegistry.addPendingAnimation("com.android.test", mAdapter);
+ mClock.fastForward(1000);
+ mHandler.timeAdvance();
+ final ActivityOptions opts = mRegistry.overrideOptionsIfNeeded("com.android.test", null);
+ assertEquals(mAdapter, opts.getRemoteAnimationAdapter());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
index 98c428dccf7a..091d9bd11a40 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
@@ -45,6 +45,7 @@ import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.TimeUnit;
/**
* Unit tests for {@link android.app.admin.SystemUpdatePolicy}.
@@ -253,6 +254,147 @@ public final class SystemUpdatePolicyTest {
}
+ @Test
+ public void testInstallationOptionWithoutFreeze() {
+ // Also duplicated at com.google.android.gts.deviceowner.SystemUpdatePolicyTest
+ final long millis_2018_01_01 = TimeUnit.SECONDS.toMillis(1514764800);
+
+ SystemUpdatePolicy p = SystemUpdatePolicy.createAutomaticInstallPolicy();
+ assertInstallationOption(SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, Long.MAX_VALUE,
+ millis_2018_01_01, p);
+
+ p = SystemUpdatePolicy.createPostponeInstallPolicy();
+ assertInstallationOption(SystemUpdatePolicy.TYPE_POSTPONE, Long.MAX_VALUE,
+ millis_2018_01_01, p);
+
+ p = SystemUpdatePolicy.createWindowedInstallPolicy(120, 180); // 2:00 - 3:00
+ // 00:00 is two hours before the next window
+ assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(2),
+ millis_2018_01_01, p);
+ // 02:00 is within the current maintenance window, and one hour until the window ends
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.HOURS.toMillis(1),
+ millis_2018_01_01 + TimeUnit.HOURS.toMillis(2), p);
+ // 04:00 is 22 hours from the window next day
+ assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(22),
+ millis_2018_01_01 + TimeUnit.HOURS.toMillis(4), p);
+
+ p = SystemUpdatePolicy.createWindowedInstallPolicy(22 * 60, 2 * 60); // 22:00 - 2:00
+ // 21:00 is one hour from the next window
+ assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(1),
+ millis_2018_01_01 + TimeUnit.HOURS.toMillis(21), p);
+ // 00:00 is two hours from the end of current window
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.HOURS.toMillis(2),
+ millis_2018_01_01, p);
+ // 03:00 is 22 hours from the window today
+ assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(19),
+ millis_2018_01_01 + TimeUnit.HOURS.toMillis(3), p);
+ }
+
+ @Test
+ public void testInstallationOptionWithFreeze() throws Exception {
+ final long millis_2016_02_29 = TimeUnit.SECONDS.toMillis(1456704000);
+ final long millis_2017_01_31 = TimeUnit.SECONDS.toMillis(1485820800);
+ final long millis_2017_02_28 = TimeUnit.SECONDS.toMillis(1488240000);
+ final long millis_2018_01_01 = TimeUnit.SECONDS.toMillis(1514764800);
+ final long millis_2018_08_01 = TimeUnit.SECONDS.toMillis(1533081600);
+
+ SystemUpdatePolicy p = SystemUpdatePolicy.createAutomaticInstallPolicy();
+ setFreezePeriods(p, "01-01", "01-31");
+ // Inside a freeze period
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(31),
+ millis_2018_01_01, p);
+ // Device is outside freeze between 2/28 to 12/31 inclusive
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(307),
+ millis_2017_02_28, p);
+
+ // Freeze period contains leap day Feb 29
+ p = SystemUpdatePolicy.createPostponeInstallPolicy();
+ setFreezePeriods(p, "02-01", "03-15");
+ // Freezed until 3/31, note 2016 is a leap year
+ assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(16),
+ millis_2016_02_29, p);
+ // Freezed until 3/31, note 2017 is not a leap year
+ assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(16),
+ millis_2017_02_28, p);
+ // Next freeze is 2018/2/1
+ assertInstallationOption(SystemUpdatePolicy.TYPE_POSTPONE, TimeUnit.DAYS.toMillis(31),
+ millis_2018_01_01, p);
+
+ // Freeze period start on or right after leap day
+ p = SystemUpdatePolicy.createAutomaticInstallPolicy();
+ setFreezePeriods(p, "03-01", "03-31");
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(1),
+ millis_2016_02_29, p);
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(1),
+ millis_2017_02_28, p);
+ setFreezePeriods(p, "02-28", "03-15");
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(16),
+ millis_2016_02_29, p);
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(16),
+ millis_2017_02_28, p);
+
+ // Freeze period end on or right after leap day
+ p = SystemUpdatePolicy.createAutomaticInstallPolicy();
+ setFreezePeriods(p, "02-01", "02-28");
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(1),
+ millis_2016_02_29, p);
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(1),
+ millis_2017_02_28, p);
+ p = SystemUpdatePolicy.createAutomaticInstallPolicy();
+ setFreezePeriods(p, "02-01", "03-01");
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(2),
+ millis_2016_02_29, p);
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(2),
+ millis_2017_02_28, p);
+
+ // Freeze period with maintenance window
+ p = SystemUpdatePolicy.createWindowedInstallPolicy(23 * 60, 1 * 60); // 23:00 - 1:00
+ setFreezePeriods(p, "02-01", "02-28");
+ // 00:00 is within the current window, outside freeze period
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.HOURS.toMillis(1),
+ millis_2018_01_01, p);
+ // Last day of feeze period, which ends in 22 hours
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(22),
+ millis_2017_02_28 + TimeUnit.HOURS.toMillis(2), p);
+ // Last day before the next freeze, and within window
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.HOURS.toMillis(1),
+ millis_2017_01_31, p);
+ // Last day before the next freeze, and there is still a partial maintenance window before
+ // the freeze.
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(19),
+ millis_2017_01_31 + TimeUnit.HOURS.toMillis(4), p);
+
+ // Two freeze periods
+ p = SystemUpdatePolicy.createAutomaticInstallPolicy();
+ setFreezePeriods(p, "05-01", "06-01", "12-01", "01-31");
+ // automatic policy for August, September, November and December
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(122),
+ millis_2018_08_01, p);
+ }
+
+ private void assertInstallationOption(int expectedType, long expectedTime, long now,
+ SystemUpdatePolicy p) {
+ assertEquals(expectedType, p.getInstallationOptionAt(now).getType());
+ assertEquals(expectedTime, p.getInstallationOptionAt(now).getEffectiveTime());
+ }
+
private void testFreezePeriodsSucceeds(String...dates) throws Exception {
SystemUpdatePolicy p = SystemUpdatePolicy.createPostponeInstallPolicy();
setFreezePeriods(p, dates);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/OWNERS b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/OWNERS
new file mode 100644
index 000000000000..bb487fb52c9f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/OWNERS
@@ -0,0 +1,4 @@
+aseemk@google.com
+bozhu@google.com
+dementyev@google.com
+robertberry@google.com
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index a523b86f3b0b..8bd0df492dee 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -503,6 +503,30 @@ public class RecoverableKeyStoreManagerTest {
}
@Test
+ public void recoverKeys_doesNotThrowIfNoApplicationKeysToBeDecrypted() throws Exception {
+ mRecoverableKeyStoreManager.startRecoverySession(
+ TEST_SESSION_ID,
+ TEST_PUBLIC_KEY,
+ TEST_VAULT_PARAMS,
+ TEST_VAULT_CHALLENGE,
+ ImmutableList.of(new KeyChainProtectionParams(
+ TYPE_LOCKSCREEN,
+ UI_FORMAT_PASSWORD,
+ KeyDerivationParams.createSha256Params(TEST_SALT),
+ TEST_SECRET)));
+ byte[] keyClaimant = mRecoverySessionStorage.get(Binder.getCallingUid(), TEST_SESSION_ID)
+ .getKeyClaimant();
+ SecretKey recoveryKey = randomRecoveryKey();
+ byte[] encryptedClaimResponse = encryptClaimResponse(
+ keyClaimant, TEST_SECRET, TEST_VAULT_PARAMS, recoveryKey);
+
+ mRecoverableKeyStoreManager.recoverKeys(
+ TEST_SESSION_ID,
+ /*encryptedRecoveryKey=*/ encryptedClaimResponse,
+ /*applicationKeys=*/ ImmutableList.of());
+ }
+
+ @Test
public void recoverKeys_returnsDecryptedKeys() throws Exception {
mRecoverableKeyStoreManager.startRecoverySession(
TEST_SESSION_ID,
diff --git a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
index 6e1808ba1e87..28b54ef84a91 100644
--- a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
@@ -323,6 +323,7 @@ public class ConnOnActivityStartTest {
private void turnBatteryOn() throws Exception {
executeCommand("cmd battery unplug");
+ executeCommand("cmd battery set status " + BatteryManager.BATTERY_STATUS_NOT_CHARGING);
assertBatteryOn();
}
@@ -336,6 +337,7 @@ public class ConnOnActivityStartTest {
private void turnBatteryOff() throws Exception {
executeCommand("cmd battery set ac " + BatteryManager.BATTERY_PLUGGED_AC);
+ executeCommand("cmd battery set status " + BatteryManager.BATTERY_STATUS_CHARGING);
}
private static void batteryReset() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 98483a80e091..53d97e7957c8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -612,7 +612,6 @@ public class PackageManagerSettingsTests {
assertThat(origPkgSetting.installerPackageName, is(testPkgSetting.installerPackageName));
assertThat(origPkgSetting.installPermissionsFixed,
is(testPkgSetting.installPermissionsFixed));
- assertThat(origPkgSetting.installStatus, is(testPkgSetting.installStatus));
assertThat(origPkgSetting.isOrphaned, is(testPkgSetting.isOrphaned));
assertSame(origPkgSetting.keySetData, testPkgSetting.keySetData);
assertThat(origPkgSetting.keySetData, is(testPkgSetting.keySetData));
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
index f559986a6f15..93064bc4ab92 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
@@ -118,7 +118,7 @@ public class DexoptOptionsTests {
public void testCreateDexoptOptionsSplit() {
int flags = DexoptOptions.DEXOPT_FORCE | DexoptOptions.DEXOPT_BOOT_COMPLETE;
- DexoptOptions opt = new DexoptOptions(mPackageName, mCompilerFilter, mSplitName, flags);
+ DexoptOptions opt = new DexoptOptions(mPackageName, -1, mCompilerFilter, mSplitName, flags);
assertEquals(mPackageName, opt.getPackageName());
assertEquals(mCompilerFilter, opt.getCompilerFilter());
assertEquals(mSplitName, opt.getSplitName());
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java
index f7516b2c3694..f7112d43443b 100644
--- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java
@@ -15,25 +15,30 @@
*/
package com.android.server.power.batterysaver;
+import static com.android.server.power.batterysaver.BatterySavingStats.SEND_TRON_EVENTS;
+
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import android.metrics.LogMaker;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.power.batterysaver.BatterySavingStats.BatterySaverState;
import com.android.server.power.batterysaver.BatterySavingStats.DozeState;
import com.android.server.power.batterysaver.BatterySavingStats.InteractiveState;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
@@ -222,8 +227,28 @@ public class BatterySavingStatsTest {
target.toDebugString());
}
- private void assertMetricsLog(String counter, int value) {
- verify(mMetricsLogger, times(1)).count(eq(counter), eq(value));
+ private void assertLog(boolean batterySaver, boolean interactive, long deltaTimeMs,
+ int deltaBatteryLevelUa, int deltaBatteryLevelPercent) {
+ if (SEND_TRON_EVENTS) {
+ ArgumentCaptor<LogMaker> ac = ArgumentCaptor.forClass(LogMaker.class);
+ verify(mMetricsLogger, times(1)).write(ac.capture());
+
+ LogMaker lm = ac.getValue();
+ assertEquals(MetricsEvent.BATTERY_SAVER, lm.getCategory());
+ assertEquals(batterySaver ? 1 : 0,
+ lm.getTaggedData(MetricsEvent.RESERVED_FOR_LOGBUILDER_SUBTYPE));
+ assertEquals(interactive ? 1 : 0, lm.getTaggedData(MetricsEvent.FIELD_INTERACTIVE));
+ assertEquals(deltaTimeMs, lm.getTaggedData(MetricsEvent.FIELD_DURATION_MILLIS));
+
+ assertEquals(deltaBatteryLevelUa,
+ (int) lm.getTaggedData(MetricsEvent.FIELD_START_BATTERY_UA)
+ - (int) lm.getTaggedData(MetricsEvent.FIELD_END_BATTERY_UA));
+ assertEquals(deltaBatteryLevelPercent,
+ (int) lm.getTaggedData(MetricsEvent.FIELD_START_BATTERY_PERCENT)
+ - (int) lm.getTaggedData(MetricsEvent.FIELD_END_BATTERY_PERCENT));
+ } else {
+ verify(mMetricsLogger, times(0)).write(any(LogMaker.class));
+ }
}
@Test
@@ -249,9 +274,7 @@ public class BatterySavingStatsTest {
InteractiveState.NON_INTERACTIVE,
DozeState.NOT_DOZING);
- assertMetricsLog(BatterySavingStats.COUNTER_POWER_MILLIAMPS_PREFIX + "01", 2);
- assertMetricsLog(BatterySavingStats.COUNTER_POWER_PERCENT_PREFIX + "01", 200);
- assertMetricsLog(BatterySavingStats.COUNTER_TIME_SECONDS_PREFIX + "01", 60);
+ assertLog(false, true, 60_000, 2000, 200);
target.advanceClock(1);
target.drainBattery(2000);
@@ -282,9 +305,7 @@ public class BatterySavingStatsTest {
InteractiveState.INTERACTIVE,
DozeState.NOT_DOZING);
- assertMetricsLog(BatterySavingStats.COUNTER_POWER_MILLIAMPS_PREFIX + "00", 2 * 3);
- assertMetricsLog(BatterySavingStats.COUNTER_POWER_PERCENT_PREFIX + "00", 200 * 3);
- assertMetricsLog(BatterySavingStats.COUNTER_TIME_SECONDS_PREFIX + "00", 60 * 3);
+ assertLog(false, false, 60_000 * 3, 2000 * 3, 200 * 3);
target.advanceClock(10);
target.drainBattery(10000);
@@ -292,9 +313,7 @@ public class BatterySavingStatsTest {
reset(mMetricsLogger);
target.startCharging();
- assertMetricsLog(BatterySavingStats.COUNTER_POWER_MILLIAMPS_PREFIX + "11", 10);
- assertMetricsLog(BatterySavingStats.COUNTER_POWER_PERCENT_PREFIX + "11", 1000);
- assertMetricsLog(BatterySavingStats.COUNTER_TIME_SECONDS_PREFIX + "11", 60 * 10);
+ assertLog(true, true, 60_000 * 10, 10000, 1000);
target.advanceClock(1);
target.drainBattery(2000);
@@ -312,8 +331,6 @@ public class BatterySavingStatsTest {
target.startCharging();
- assertMetricsLog(BatterySavingStats.COUNTER_POWER_MILLIAMPS_PREFIX + "10", 2);
- assertMetricsLog(BatterySavingStats.COUNTER_POWER_PERCENT_PREFIX + "10", 200);
- assertMetricsLog(BatterySavingStats.COUNTER_TIME_SECONDS_PREFIX + "10", 60);
+ assertLog(true, false, 60_000, 2000, 200);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java b/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java
index 029d9f1a8262..1222b59e92b9 100644
--- a/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java
+++ b/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java
@@ -16,10 +16,11 @@
package com.android.server.testutils;
-import static android.util.ExceptionUtils.getRootCause;
+import static android.util.ExceptionUtils.appendCause;
import static android.util.ExceptionUtils.propagate;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.util.ArrayMap;
@@ -60,7 +61,7 @@ public class TestHandler extends Handler {
}
public TestHandler(Callback callback, LongSupplier clock) {
- super(callback);
+ super(Looper.getMainLooper(), callback);
mClock = clock;
}
@@ -132,7 +133,7 @@ public class TestHandler extends Handler {
} catch (Throwable t) {
// Append stack trace of this message being posted as a cause for a helpful
// test error message
- throw propagate(getRootCause(t).initCause(msg.postPoint));
+ throw propagate(appendCause(t, msg.postPoint));
} finally {
msg.message.recycle();
}
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 78b6077dc1bd..cbbdca6b394f 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -308,6 +308,7 @@ public class AppStandbyControllerTests {
private void reportEvent(AppStandbyController controller, int eventType,
long elapsedTime) {
// Back to ACTIVE on event
+ mInjector.mElapsedRealtime = elapsedTime;
UsageEvents.Event ev = new UsageEvents.Event();
ev.mPackage = PACKAGE_1;
ev.mEventType = eventType;
@@ -487,6 +488,89 @@ public class AppStandbyControllerTests {
}
@Test
+ public void testCascadingTimeouts() throws Exception {
+ setChargingState(mController, false);
+
+ reportEvent(mController, USER_INTERACTION, 0);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ reportEvent(mController, NOTIFICATION_SEEN, 1000);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
+ REASON_PREDICTED, 1000);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
+ REASON_PREDICTED, 2000 + mController.mStrongUsageTimeoutMillis);
+ assertBucket(STANDBY_BUCKET_WORKING_SET);
+
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
+ REASON_PREDICTED, 2000 + mController.mNotificationSeenTimeoutMillis);
+ assertBucket(STANDBY_BUCKET_FREQUENT);
+ }
+
+ @Test
+ public void testOverlappingTimeouts() throws Exception {
+ setChargingState(mController, false);
+
+ reportEvent(mController, USER_INTERACTION, 0);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ reportEvent(mController, NOTIFICATION_SEEN, 1000);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ // Overlapping USER_INTERACTION before previous one times out
+ reportEvent(mController, USER_INTERACTION, mController.mStrongUsageTimeoutMillis - 1000);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ // Still in ACTIVE after first USER_INTERACTION times out
+ mInjector.mElapsedRealtime = mController.mStrongUsageTimeoutMillis + 1000;
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
+ REASON_PREDICTED, mInjector.mElapsedRealtime);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ // Both timed out, so NOTIFICATION_SEEN timeout should be effective
+ mInjector.mElapsedRealtime = mController.mStrongUsageTimeoutMillis * 2 + 2000;
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
+ REASON_PREDICTED, mInjector.mElapsedRealtime);
+ assertBucket(STANDBY_BUCKET_WORKING_SET);
+
+ mInjector.mElapsedRealtime = mController.mNotificationSeenTimeoutMillis + 2000;
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
+ REASON_PREDICTED, mInjector.mElapsedRealtime);
+ assertBucket(STANDBY_BUCKET_RARE);
+ }
+
+ @Test
+ public void testPredictionNotOverridden() throws Exception {
+ setChargingState(mController, false);
+
+ reportEvent(mController, USER_INTERACTION, 0);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ mInjector.mElapsedRealtime = WORKING_SET_THRESHOLD - 1000;
+ reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ // Falls back to WORKING_SET
+ mInjector.mElapsedRealtime += 5000;
+ mController.checkIdleStates(USER_ID);
+ assertBucket(STANDBY_BUCKET_WORKING_SET);
+
+ // Predict to ACTIVE
+ mInjector.mElapsedRealtime += 1000;
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
+ REASON_PREDICTED, mInjector.mElapsedRealtime);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ // CheckIdleStates should not change the prediction
+ mInjector.mElapsedRealtime += 1000;
+ mController.checkIdleStates(USER_ID);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+ }
+
+ @Test
public void testAddActiveDeviceAdmin() {
assertActiveAdmins(USER_ID, (String[]) null);
assertActiveAdmins(USER_ID2, (String[]) null);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index 920796ed6a30..5650050f0420 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -29,6 +29,7 @@ import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.ArraySet;
+import com.google.android.collect.Sets;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -74,6 +75,21 @@ public class TaskSnapshotControllerTest extends WindowTestsBase {
}
@Test
+ public void testGetClosingApps_skipClosingAppsSnapshotTasks() throws Exception {
+ final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
+ "closingWindow");
+ closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET,
+ true /* performLayout */, false /* isVoiceInteraction */);
+ final ArraySet<AppWindowToken> closingApps = new ArraySet<>();
+ closingApps.add(closingWindow.mAppToken);
+ final ArraySet<Task> closingTasks = new ArraySet<>();
+ sWm.mTaskSnapshotController.addSkipClosingAppSnapshotTasks(
+ Sets.newArraySet(closingWindow.mAppToken.getTask()));
+ sWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
+ assertEquals(0, closingTasks.size());
+ }
+
+ @Test
public void testGetSnapshotMode() throws Exception {
final WindowState disabledWindow = createWindow(null,
FIRST_APPLICATION_WINDOW, mDisplayContent, "disabledWindow");
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index c532a8a25bda..6144c516750d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -17,21 +17,32 @@
package com.android.server.notification;
import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertEquals;
import static junit.framework.TestCase.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import android.app.NotificationManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
import android.media.AudioAttributes;
import android.provider.Settings;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.server.UiServiceTestCase;
import org.junit.Before;
@@ -46,15 +57,24 @@ import org.mockito.MockitoAnnotations;
public class ZenModeHelperTest extends UiServiceTestCase {
@Mock ConditionProviders mConditionProviders;
+ @Mock NotificationManager mNotificationManager;
+ @Mock private Resources mResources;
private TestableLooper mTestableLooper;
private ZenModeHelper mZenModeHelperSpy;
+ private Context mContext;
+ private ContentResolver mContentResolver;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mTestableLooper = TestableLooper.get(this);
- mZenModeHelperSpy = spy(new ZenModeHelper(getContext(), mTestableLooper.getLooper(),
+ mContext = spy(getContext());
+ mContentResolver = mContext.getContentResolver();
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mContext.getSystemService(NotificationManager.class)).thenReturn(mNotificationManager);
+
+ mZenModeHelperSpy = spy(new ZenModeHelper(mContext, mTestableLooper.getLooper(),
mConditionProviders));
}
@@ -194,4 +214,31 @@ public class ZenModeHelperTest extends UiServiceTestCase {
verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(shouldMute, usage);
}
}
+
+ @Test
+ public void testZenUpgradeNotification() {
+ // shows zen upgrade notification if stored settings says to shows, boot is completed
+ // and we're setting zen mode on
+ Settings.Global.putInt(mContentResolver, Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 1);
+ mZenModeHelperSpy.mIsBootComplete = true;
+ mZenModeHelperSpy.setZenModeSetting(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+
+ verify(mZenModeHelperSpy, times(1)).createZenUpgradeNotification();
+ verify(mNotificationManager, times(1)).notify(eq(ZenModeHelper.TAG),
+ eq(SystemMessage.NOTE_ZEN_UPGRADE), any());
+ assertEquals(0, Settings.Global.getInt(mContentResolver,
+ Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION, -1));
+ }
+
+ @Test
+ public void testNoZenUpgradeNotification() {
+ // doesn't show upgrade notification if stored settings says don't show
+ Settings.Global.putInt(mContentResolver, Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
+ mZenModeHelperSpy.mIsBootComplete = true;
+ mZenModeHelperSpy.setZenModeSetting(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+
+ verify(mZenModeHelperSpy, never()).createZenUpgradeNotification();
+ verify(mNotificationManager, never()).notify(eq(ZenModeHelper.TAG),
+ eq(SystemMessage.NOTE_ZEN_UPGRADE), any());
+ }
}
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index b654a66f7d30..f26c2ae771f0 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -23,6 +23,7 @@ import static android.app.usage.UsageStatsManager.REASON_USAGE;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
import android.app.usage.UsageStatsManager;
import android.os.SystemClock;
@@ -87,7 +88,9 @@ public class AppIdleHistory {
// The last time a job was run for this app
private static final String ATTR_LAST_RUN_JOB_TIME = "lastJobRunTime";
// The time when the forced active state can be overridden.
- private static final String ATTR_BUCKET_TIMEOUT_TIME = "bucketTimeoutTime";
+ private static final String ATTR_BUCKET_ACTIVE_TIMEOUT_TIME = "activeTimeoutTime";
+ // The time when the forced working_set state can be overridden.
+ private static final String ATTR_BUCKET_WORKING_SET_TIMEOUT_TIME = "workingSetTimeoutTime";
// device on time = mElapsedDuration + (timeNow - mElapsedSnapshot)
private long mElapsedSnapshot; // Elapsed time snapshot when last write of mDeviceOnDuration
@@ -117,11 +120,15 @@ public class AppIdleHistory {
int lastInformedBucket;
// The last time a job was run for this app, using elapsed timebase
long lastJobRunTime;
- // When should the bucket state timeout, in elapsed timebase, if greater than
+ // When should the bucket active state timeout, in elapsed timebase, if greater than
// lastUsedElapsedTime.
// This is used to keep the app in a high bucket regardless of other timeouts and
// predictions.
- long bucketTimeoutTime;
+ long bucketActiveTimeoutTime;
+ // If there's a forced working_set state, this is when it times out. This can be sitting
+ // under any active state timeout, so that it becomes applicable after the active state
+ // timeout expires.
+ long bucketWorkingSetTimeoutTime;
}
AppIdleHistory(File storageDir, long elapsedRealtime) {
@@ -208,11 +215,28 @@ public class AppIdleHistory {
* @param packageName name of the app being updated, for logging purposes
* @param newBucket the bucket to set the app to
* @param elapsedRealtime mark as used time if non-zero
- * @param timeout set the timeout of the specified bucket, if non-zero
+ * @param timeout set the timeout of the specified bucket, if non-zero. Can only be used
+ * with bucket values of ACTIVE and WORKING_SET.
* @return
*/
public AppUsageHistory reportUsage(AppUsageHistory appUsageHistory, String packageName,
int newBucket, long elapsedRealtime, long timeout) {
+ // Set the timeout if applicable
+ if (timeout > elapsedRealtime) {
+ // Convert to elapsed timebase
+ final long timeoutTime = mElapsedDuration + (timeout - mElapsedSnapshot);
+ if (newBucket == STANDBY_BUCKET_ACTIVE) {
+ appUsageHistory.bucketActiveTimeoutTime = Math.max(timeoutTime,
+ appUsageHistory.bucketActiveTimeoutTime);
+ } else if (newBucket == STANDBY_BUCKET_WORKING_SET) {
+ appUsageHistory.bucketWorkingSetTimeoutTime = Math.max(timeoutTime,
+ appUsageHistory.bucketWorkingSetTimeoutTime);
+ } else {
+ throw new IllegalArgumentException("Cannot set a timeout on bucket=" +
+ newBucket);
+ }
+ }
+
if (elapsedRealtime != 0) {
appUsageHistory.lastUsedElapsedTime = mElapsedDuration
+ (elapsedRealtime - mElapsedSnapshot);
@@ -226,12 +250,6 @@ public class AppIdleHistory {
.currentBucket
+ ", reason=" + appUsageHistory.bucketingReason);
}
- if (timeout > elapsedRealtime) {
- // Convert to elapsed timebase
- appUsageHistory.bucketTimeoutTime =
- Math.max(appUsageHistory.bucketTimeoutTime,
- mElapsedDuration + (timeout - mElapsedSnapshot));
- }
}
appUsageHistory.bucketingReason = REASON_USAGE;
@@ -247,7 +265,8 @@ public class AppIdleHistory {
* @param userId
* @param newBucket the bucket to set the app to
* @param elapsedRealtime mark as used time if non-zero
- * @param timeout set the timeout of the specified bucket, if non-zero
+ * @param timeout set the timeout of the specified bucket, if non-zero. Can only be used
+ * with bucket values of ACTIVE and WORKING_SET.
* @return
*/
public AppUsageHistory reportUsage(String packageName, int userId, int newBucket,
@@ -504,8 +523,10 @@ public class AppIdleHistory {
parser.getAttributeValue(null, ATTR_BUCKETING_REASON);
appUsageHistory.lastJobRunTime = getLongValue(parser,
ATTR_LAST_RUN_JOB_TIME, Long.MIN_VALUE);
- appUsageHistory.bucketTimeoutTime = getLongValue(parser,
- ATTR_BUCKET_TIMEOUT_TIME, 0L);
+ appUsageHistory.bucketActiveTimeoutTime = getLongValue(parser,
+ ATTR_BUCKET_ACTIVE_TIMEOUT_TIME, 0L);
+ appUsageHistory.bucketWorkingSetTimeoutTime = getLongValue(parser,
+ ATTR_BUCKET_WORKING_SET_TIMEOUT_TIME, 0L);
if (appUsageHistory.bucketingReason == null) {
appUsageHistory.bucketingReason = REASON_DEFAULT;
}
@@ -557,9 +578,13 @@ public class AppIdleHistory {
xml.attribute(null, ATTR_CURRENT_BUCKET,
Integer.toString(history.currentBucket));
xml.attribute(null, ATTR_BUCKETING_REASON, history.bucketingReason);
- if (history.bucketTimeoutTime > 0) {
- xml.attribute(null, ATTR_BUCKET_TIMEOUT_TIME, Long.toString(history
- .bucketTimeoutTime));
+ if (history.bucketActiveTimeoutTime > 0) {
+ xml.attribute(null, ATTR_BUCKET_ACTIVE_TIMEOUT_TIME, Long.toString(history
+ .bucketActiveTimeoutTime));
+ }
+ if (history.bucketWorkingSetTimeoutTime > 0) {
+ xml.attribute(null, ATTR_BUCKET_WORKING_SET_TIMEOUT_TIME, Long.toString(history
+ .bucketWorkingSetTimeoutTime));
}
if (history.lastJobRunTime != Long.MIN_VALUE) {
xml.attribute(null, ATTR_LAST_RUN_JOB_TIME, Long.toString(history
@@ -593,14 +618,19 @@ public class AppIdleHistory {
continue;
}
idpw.print("package=" + packageName);
+ idpw.print(" userId=" + userId);
idpw.print(" lastUsedElapsed=");
TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastUsedElapsedTime, idpw);
idpw.print(" lastUsedScreenOn=");
TimeUtils.formatDuration(screenOnTime - appUsageHistory.lastUsedScreenTime, idpw);
idpw.print(" lastPredictedTime=");
TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastPredictedTime, idpw);
- idpw.print(" bucketTimeoutTime=");
- TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.bucketTimeoutTime, idpw);
+ idpw.print(" bucketActiveTimeoutTime=");
+ TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.bucketActiveTimeoutTime,
+ idpw);
+ idpw.print(" bucketWorkingSetTimeoutTime=");
+ TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.bucketWorkingSetTimeoutTime,
+ idpw);
idpw.print(" lastJobRunTime=");
TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastJobRunTime, idpw);
idpw.print(" idle=" + (isIdle(packageName, userId, elapsedRealtime) ? "y" : "n"));
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 32db7526f3c0..c31809e913ad 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -30,6 +30,7 @@ import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
+import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.usage.UsageStatsManager.StandbyBuckets;
@@ -171,6 +172,8 @@ public class AppStandbyController {
static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
static final int MSG_PAROLE_STATE_CHANGED = 9;
static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
+ /** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */
+ static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11;
long mCheckIdleIntervalMillis;
long mAppIdleParoleIntervalMillis;
@@ -322,7 +325,7 @@ public class AppStandbyController {
// Get sync adapters for the authority
String[] packages = ContentResolver.getSyncAdapterPackagesForAuthorityAsUser(
authority, userId);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long elapsedRealtime = mInjector.elapsedRealtime();
for (String packageName: packages) {
// Only force the sync adapters to active if the provider is not in the same package and
// the sync adapter is a system package.
@@ -460,53 +463,8 @@ public class AppStandbyController {
for (int p = 0; p < packageCount; p++) {
final PackageInfo pi = packages.get(p);
final String packageName = pi.packageName;
- final boolean isSpecial = isAppSpecial(packageName,
- UserHandle.getAppId(pi.applicationInfo.uid),
- userId);
- if (DEBUG) {
- Slog.d(TAG, " Checking idle state for " + packageName + " special=" +
- isSpecial);
- }
- if (isSpecial) {
- synchronized (mAppIdleLock) {
- mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
- STANDBY_BUCKET_EXEMPTED, REASON_DEFAULT);
- }
- maybeInformListeners(packageName, userId, elapsedRealtime,
- STANDBY_BUCKET_EXEMPTED, false);
- } else {
- synchronized (mAppIdleLock) {
- AppIdleHistory.AppUsageHistory app =
- mAppIdleHistory.getAppUsageHistory(packageName,
- userId, elapsedRealtime);
- // If the bucket was forced by the developer or the app is within the
- // temporary active period, leave it alone.
- if (REASON_FORCED.equals(app.bucketingReason)
- || !hasBucketTimeoutPassed(app, elapsedRealtime)) {
- continue;
- }
- boolean predictionLate = false;
- // If the bucket was moved up due to usage, let the timeouts apply.
- if (REASON_DEFAULT.equals(app.bucketingReason)
- || REASON_USAGE.equals(app.bucketingReason)
- || REASON_TIMEOUT.equals(app.bucketingReason)
- || (predictionLate = predictionTimedOut(app, elapsedRealtime))) {
- int oldBucket = app.currentBucket;
- int newBucket = getBucketForLocked(packageName, userId,
- elapsedRealtime);
- if (DEBUG) {
- Slog.d(TAG, " Old bucket=" + oldBucket
- + ", newBucket=" + newBucket);
- }
- if (oldBucket < newBucket || predictionLate) {
- mAppIdleHistory.setAppStandbyBucket(packageName, userId,
- elapsedRealtime, newBucket, REASON_TIMEOUT);
- maybeInformListeners(packageName, userId, elapsedRealtime,
- newBucket, false);
- }
- }
- }
- }
+ checkAndUpdateStandbyState(packageName, userId, pi.applicationInfo.uid,
+ elapsedRealtime);
}
}
if (DEBUG) {
@@ -516,6 +474,90 @@ public class AppStandbyController {
return true;
}
+ /** Check if we need to update the standby state of a specific app. */
+ private void checkAndUpdateStandbyState(String packageName, @UserIdInt int userId,
+ int uid, long elapsedRealtime) {
+ if (uid <= 0) {
+ try {
+ uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Not a valid package for this user, nothing to do
+ // TODO: Remove any history of removed packages
+ return;
+ }
+ }
+ final boolean isSpecial = isAppSpecial(packageName,
+ UserHandle.getAppId(uid),
+ userId);
+ if (DEBUG) {
+ Slog.d(TAG, " Checking idle state for " + packageName + " special=" +
+ isSpecial);
+ }
+ if (isSpecial) {
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
+ STANDBY_BUCKET_EXEMPTED, REASON_DEFAULT);
+ }
+ maybeInformListeners(packageName, userId, elapsedRealtime,
+ STANDBY_BUCKET_EXEMPTED, false);
+ } else {
+ synchronized (mAppIdleLock) {
+ final AppIdleHistory.AppUsageHistory app =
+ mAppIdleHistory.getAppUsageHistory(packageName,
+ userId, elapsedRealtime);
+ String reason = app.bucketingReason;
+
+ // If the bucket was forced by the user/developer, leave it alone.
+ // A usage event will be the only way to bring it out of this forced state
+ if (REASON_FORCED.equals(app.bucketingReason)) {
+ return;
+ }
+ final int oldBucket = app.currentBucket;
+ int newBucket = Math.max(oldBucket, STANDBY_BUCKET_ACTIVE); // Undo EXEMPTED
+ boolean predictionLate = false;
+ // Compute age-based bucket
+ if (REASON_DEFAULT.equals(app.bucketingReason)
+ || REASON_USAGE.equals(app.bucketingReason)
+ || REASON_TIMEOUT.equals(app.bucketingReason)
+ || (predictionLate = predictionTimedOut(app, elapsedRealtime))) {
+ newBucket = getBucketForLocked(packageName, userId,
+ elapsedRealtime);
+ if (DEBUG) {
+ Slog.d(TAG, "Evaluated AOSP newBucket = " + newBucket);
+ }
+ reason = REASON_TIMEOUT;
+ }
+ // Check if the app is within one of the timeouts for forced bucket elevation
+ final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
+ if (newBucket >= STANDBY_BUCKET_ACTIVE
+ && app.bucketActiveTimeoutTime > elapsedTimeAdjusted) {
+ newBucket = STANDBY_BUCKET_ACTIVE;
+ reason = REASON_USAGE;
+ if (DEBUG) {
+ Slog.d(TAG, " Keeping at ACTIVE due to min timeout");
+ }
+ } else if (newBucket >= STANDBY_BUCKET_WORKING_SET
+ && app.bucketWorkingSetTimeoutTime > elapsedTimeAdjusted) {
+ newBucket = STANDBY_BUCKET_WORKING_SET;
+ reason = REASON_USAGE;
+ if (DEBUG) {
+ Slog.d(TAG, " Keeping at WORKING_SET due to min timeout");
+ }
+ }
+ if (DEBUG) {
+ Slog.d(TAG, " Old bucket=" + oldBucket
+ + ", newBucket=" + newBucket);
+ }
+ if (oldBucket < newBucket || predictionLate) {
+ mAppIdleHistory.setAppStandbyBucket(packageName, userId,
+ elapsedRealtime, newBucket, reason);
+ maybeInformListeners(packageName, userId, elapsedRealtime,
+ newBucket, false);
+ }
+ }
+ }
+ }
+
private boolean predictionTimedOut(AppIdleHistory.AppUsageHistory app, long elapsedRealtime) {
return app.bucketingReason != null
&& app.bucketingReason.startsWith(REASON_PREDICTED)
@@ -526,7 +568,9 @@ public class AppStandbyController {
private boolean hasBucketTimeoutPassed(AppIdleHistory.AppUsageHistory app,
long elapsedRealtime) {
- return app.bucketTimeoutTime < mAppIdleHistory.getElapsedTime(elapsedRealtime);
+ final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
+ return app.bucketActiveTimeoutTime < elapsedTimeAdjusted
+ && app.bucketWorkingSetTimeoutTime < elapsedTimeAdjusted;
}
private void maybeInformListeners(String packageName, int userId,
@@ -631,16 +675,22 @@ public class AppStandbyController {
event.mPackage, userId, elapsedRealtime);
final int prevBucket = appHistory.currentBucket;
final String prevBucketReason = appHistory.bucketingReason;
+ final long nextCheckTime;
if (event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN) {
+ // Mild usage elevates to WORKING_SET but doesn't change usage time.
mAppIdleHistory.reportUsage(appHistory, event.mPackage,
STANDBY_BUCKET_WORKING_SET,
- elapsedRealtime, elapsedRealtime + mNotificationSeenTimeoutMillis);
+ 0, elapsedRealtime + mNotificationSeenTimeoutMillis);
+ nextCheckTime = mNotificationSeenTimeoutMillis;
} else {
- mAppIdleHistory.reportUsage(event.mPackage, userId,
+ mAppIdleHistory.reportUsage(appHistory, event.mPackage,
STANDBY_BUCKET_ACTIVE,
elapsedRealtime, elapsedRealtime + mStrongUsageTimeoutMillis);
+ nextCheckTime = mStrongUsageTimeoutMillis;
}
-
+ mHandler.sendMessageDelayed(mHandler.obtainMessage
+ (MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, event.mPackage),
+ nextCheckTime);
final boolean userStartedInteracting =
appHistory.currentBucket == STANDBY_BUCKET_ACTIVE &&
prevBucket != appHistory.currentBucket &&
@@ -932,9 +982,24 @@ public class AppStandbyController {
// If the bucket is required to stay in a higher state for a specified duration, don't
// override unless the duration has passed
- if (predicted && app.currentBucket < newBucket
- && !hasBucketTimeoutPassed(app, elapsedRealtime)) {
- return;
+ if (predicted) {
+ // Check if the app is within one of the timeouts for forced bucket elevation
+ final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
+ if (newBucket > STANDBY_BUCKET_ACTIVE
+ && app.bucketActiveTimeoutTime > elapsedTimeAdjusted) {
+ newBucket = STANDBY_BUCKET_ACTIVE;
+ reason = REASON_USAGE;
+ if (DEBUG) {
+ Slog.d(TAG, " Keeping at ACTIVE due to min timeout");
+ }
+ } else if (newBucket > STANDBY_BUCKET_WORKING_SET
+ && app.bucketWorkingSetTimeoutTime > elapsedTimeAdjusted) {
+ newBucket = STANDBY_BUCKET_WORKING_SET;
+ reason = REASON_USAGE;
+ if (DEBUG) {
+ Slog.d(TAG, " Keeping at WORKING_SET due to min timeout");
+ }
+ }
}
mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket,
@@ -1347,6 +1412,10 @@ public class AppStandbyController {
+ ", Charging state:" + mCharging);
informParoleStateChanged();
break;
+ case MSG_CHECK_PACKAGE_IDLE_STATE:
+ checkAndUpdateStandbyState((String) msg.obj, msg.arg1, msg.arg2,
+ mInjector.elapsedRealtime());
+ break;
default:
super.handleMessage(msg);
break;
diff --git a/services/usb/OWNERS b/services/usb/OWNERS
new file mode 100644
index 000000000000..7897a0c8555c
--- /dev/null
+++ b/services/usb/OWNERS
@@ -0,0 +1,4 @@
+badhri@google.com
+elaurent@google.com
+moltmann@google.com
+zhangjerry@google.com
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
index 7480e5662d7a..9d4db003a297 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
@@ -17,9 +17,14 @@
package com.android.server.usb;
import android.annotation.NonNull;
+import android.media.AudioSystem;
+import android.media.IAudioService;
+import android.os.RemoteException;
import android.service.usb.UsbAlsaDeviceProto;
+import android.util.Slog;
import com.android.internal.util.dump.DualDumpOutputStream;
+import com.android.server.audio.AudioService;
/**
* Represents the ALSA specification, and attributes of an ALSA device.
@@ -30,25 +35,31 @@ public final class UsbAlsaDevice {
private final int mCardNum;
private final int mDeviceNum;
- private final boolean mHasPlayback;
- private final boolean mHasCapture;
+ private final String mDeviceAddress;
+ private final boolean mHasOutput;
+ private final boolean mHasInput;
private final boolean mIsInputHeadset;
private final boolean mIsOutputHeadset;
- private final String mDeviceAddress;
+ private boolean mSelected = false;
+ private int mOutputState;
+ private int mInputState;
+ private UsbAlsaJackDetector mJackDetector;
+ private IAudioService mAudioService;
private String mDeviceName = "";
private String mDeviceDescription = "";
- public UsbAlsaDevice(int card, int device, String deviceAddress,
- boolean hasPlayback, boolean hasCapture,
+ public UsbAlsaDevice(IAudioService audioService, int card, int device, String deviceAddress,
+ boolean hasOutput, boolean hasInput,
boolean isInputHeadset, boolean isOutputHeadset) {
+ mAudioService = audioService;
mCardNum = card;
mDeviceNum = device;
mDeviceAddress = deviceAddress;
- mHasPlayback = hasPlayback;
- mHasCapture = hasCapture;
+ mHasOutput = hasOutput;
+ mHasInput = hasInput;
mIsInputHeadset = isInputHeadset;
mIsOutputHeadset = isOutputHeadset;
}
@@ -75,71 +86,187 @@ public final class UsbAlsaDevice {
}
/**
- * @returns true if the device supports playback.
+ * @returns the ALSA card/device address string.
*/
- public boolean hasPlayback() {
- return mHasPlayback;
+ public String getAlsaCardDeviceString() {
+ if (mCardNum < 0 || mDeviceNum < 0) {
+ Slog.e(TAG, "Invalid alsa card or device alsaCard: " + mCardNum
+ + " alsaDevice: " + mDeviceNum);
+ return null;
+ }
+ return AudioService.makeAlsaAddressString(mCardNum, mDeviceNum);
}
/**
- * @returns true if the device supports capture (recording).
+ * @returns true if the device supports output.
*/
- public boolean hasCapture() {
- return mHasCapture;
+ public boolean hasOutput() {
+ return mHasOutput;
}
/**
- * @returns true if the device is a headset for purposes of capture.
+ * @returns true if the device supports input (recording).
+ */
+ public boolean hasInput() {
+ return mHasInput;
+ }
+
+ /**
+ * @returns true if the device is a headset for purposes of input.
*/
public boolean isInputHeadset() {
return mIsInputHeadset;
}
/**
- * @returns true if the device is a headset for purposes of playback.
+ * @returns true if the device is a headset for purposes of output.
*/
public boolean isOutputHeadset() {
return mIsOutputHeadset;
}
/**
+ * @returns true if input jack is detected or jack detection is not supported.
+ */
+ private synchronized boolean isInputJackConnected() {
+ if (mJackDetector == null) {
+ return true; // If jack detect isn't supported, say it's connected.
+ }
+ return mJackDetector.isInputJackConnected();
+ }
+
+ /**
+ * @returns true if input jack is detected or jack detection is not supported.
+ */
+ private synchronized boolean isOutputJackConnected() {
+ if (mJackDetector == null) {
+ return true; // if jack detect isn't supported, say it's connected.
+ }
+ return mJackDetector.isOutputJackConnected();
+ }
+
+ /** Begins a jack-detection thread. */
+ private synchronized void startJackDetect() {
+ // If no jack detect capabilities exist, mJackDetector will be null.
+ mJackDetector = UsbAlsaJackDetector.startJackDetect(this);
+ }
+
+ /** Stops a jack-detection thread. */
+ private synchronized void stopJackDetect() {
+ if (mJackDetector != null) {
+ mJackDetector.pleaseStop();
+ }
+ mJackDetector = null;
+ }
+
+ /** Start using this device as the selected USB Audio Device. */
+ public synchronized void start() {
+ mSelected = true;
+ mInputState = 0;
+ mOutputState = 0;
+ startJackDetect();
+ updateWiredDeviceConnectionState(true);
+ }
+
+ /** Stop using this device as the selected USB Audio Device. */
+ public synchronized void stop() {
+ stopJackDetect();
+ updateWiredDeviceConnectionState(false);
+ mSelected = false;
+ }
+
+ /** Updates AudioService with the connection state of the alsaDevice.
+ * Checks ALSA Jack state for inputs and outputs before reporting.
+ */
+ public synchronized void updateWiredDeviceConnectionState(boolean enable) {
+ if (!mSelected) {
+ Slog.e(TAG, "updateWiredDeviceConnectionState on unselected AlsaDevice!");
+ return;
+ }
+ String alsaCardDeviceString = getAlsaCardDeviceString();
+ if (alsaCardDeviceString == null) {
+ return;
+ }
+ try {
+ // Output Device
+ if (mHasOutput) {
+ int device = mIsOutputHeadset
+ ? AudioSystem.DEVICE_OUT_USB_HEADSET
+ : AudioSystem.DEVICE_OUT_USB_DEVICE;
+ if (DEBUG) {
+ Slog.d(TAG, "pre-call device:0x" + Integer.toHexString(device)
+ + " addr:" + alsaCardDeviceString
+ + " name:" + mDeviceName);
+ }
+ boolean connected = isOutputJackConnected();
+ Slog.i(TAG, "OUTPUT JACK connected: " + connected);
+ int outputState = (enable && connected) ? 1 : 0;
+ if (outputState != mOutputState) {
+ mOutputState = outputState;
+ mAudioService.setWiredDeviceConnectionState(device, outputState,
+ alsaCardDeviceString,
+ mDeviceName, TAG);
+ }
+ }
+
+ // Input Device
+ if (mHasInput) {
+ int device = mIsInputHeadset ? AudioSystem.DEVICE_IN_USB_HEADSET
+ : AudioSystem.DEVICE_IN_USB_DEVICE;
+ boolean connected = isInputJackConnected();
+ Slog.i(TAG, "INPUT JACK connected: " + connected);
+ int inputState = (enable && connected) ? 1 : 0;
+ if (inputState != mInputState) {
+ mInputState = inputState;
+ mAudioService.setWiredDeviceConnectionState(
+ device, inputState, alsaCardDeviceString,
+ mDeviceName, TAG);
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException in setWiredDeviceConnectionState");
+ }
+ }
+
+
+ /**
* @Override
* @returns a string representation of the object.
*/
- public String toString() {
+ public synchronized String toString() {
return "UsbAlsaDevice: [card: " + mCardNum
+ ", device: " + mDeviceNum
+ ", name: " + mDeviceName
- + ", hasPlayback: " + mHasPlayback
- + ", hasCapture: " + mHasCapture + "]";
+ + ", hasOutput: " + mHasOutput
+ + ", hasInput: " + mHasInput + "]";
}
/**
* Write a description of the device to a dump stream.
*/
- public void dump(@NonNull DualDumpOutputStream dump, String idName, long id) {
+ public synchronized void dump(@NonNull DualDumpOutputStream dump, String idName, long id) {
long token = dump.start(idName, id);
dump.write("card", UsbAlsaDeviceProto.CARD, mCardNum);
dump.write("device", UsbAlsaDeviceProto.DEVICE, mDeviceNum);
dump.write("name", UsbAlsaDeviceProto.NAME, mDeviceName);
- dump.write("has_playback", UsbAlsaDeviceProto.HAS_PLAYBACK, mHasPlayback);
- dump.write("has_capture", UsbAlsaDeviceProto.HAS_CAPTURE, mHasCapture);
+ dump.write("has_output", UsbAlsaDeviceProto.HAS_PLAYBACK, mHasOutput);
+ dump.write("has_input", UsbAlsaDeviceProto.HAS_CAPTURE, mHasInput);
dump.write("address", UsbAlsaDeviceProto.ADDRESS, mDeviceAddress);
dump.end(token);
}
// called by logDevices
- String toShortString() {
+ synchronized String toShortString() {
return "[card:" + mCardNum + " device:" + mDeviceNum + " " + mDeviceName + "]";
}
- String getDeviceName() {
+ synchronized String getDeviceName() {
return mDeviceName;
}
- void setDeviceNameAndDescription(String deviceName, String deviceDescription) {
+ synchronized void setDeviceNameAndDescription(String deviceName, String deviceDescription) {
mDeviceName = deviceName;
mDeviceDescription = deviceDescription;
}
@@ -155,8 +282,8 @@ public final class UsbAlsaDevice {
UsbAlsaDevice other = (UsbAlsaDevice) obj;
return (mCardNum == other.mCardNum
&& mDeviceNum == other.mDeviceNum
- && mHasPlayback == other.mHasPlayback
- && mHasCapture == other.mHasCapture
+ && mHasOutput == other.mHasOutput
+ && mHasInput == other.mHasInput
&& mIsInputHeadset == other.mIsInputHeadset
&& mIsOutputHeadset == other.mIsOutputHeadset);
}
@@ -170,8 +297,8 @@ public final class UsbAlsaDevice {
int result = 1;
result = prime * result + mCardNum;
result = prime * result + mDeviceNum;
- result = prime * result + (mHasPlayback ? 0 : 1);
- result = prime * result + (mHasCapture ? 0 : 1);
+ result = prime * result + (mHasOutput ? 0 : 1);
+ result = prime * result + (mHasInput ? 0 : 1);
result = prime * result + (mIsInputHeadset ? 0 : 1);
result = prime * result + (mIsOutputHeadset ? 0 : 1);
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaJackDetector.java b/services/usb/java/com/android/server/usb/UsbAlsaJackDetector.java
new file mode 100644
index 000000000000..c4988478df71
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/UsbAlsaJackDetector.java
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+package com.android.server.usb;
+
+/**
+ * Detects and reports ALSA jack state and events.
+ */
+public final class UsbAlsaJackDetector implements Runnable {
+ private static final String TAG = "UsbAlsaJackDetector";
+
+ private static native boolean nativeHasJackDetect(int card);
+ private native boolean nativeJackDetect(int card);
+ private native boolean nativeOutputJackConnected(int card);
+ private native boolean nativeInputJackConnected(int card);
+
+ private boolean mStopJackDetect = false;
+ private UsbAlsaDevice mAlsaDevice;
+
+ /* use startJackDetect to create a UsbAlsaJackDetector */
+ private UsbAlsaJackDetector(UsbAlsaDevice device) {
+ mAlsaDevice = device;
+ }
+
+ /** If jack detection is detected on the given Alsa Device,
+ * create and return a UsbAlsaJackDetector which will update wired device state
+ * each time a jack detection event is registered.
+ *
+ * @returns UsbAlsaJackDetector if jack detect is supported, or null.
+ */
+ public static UsbAlsaJackDetector startJackDetect(UsbAlsaDevice device) {
+ if (!nativeHasJackDetect(device.getCardNum())) {
+ return null;
+ }
+ UsbAlsaJackDetector jackDetector = new UsbAlsaJackDetector(device);
+
+ // This thread will exit once the USB device disappears.
+ // It can also be convinced to stop with pleaseStop().
+ new Thread(jackDetector, "USB jack detect thread").start();
+ return jackDetector;
+ }
+
+ public boolean isInputJackConnected() {
+ return nativeInputJackConnected(mAlsaDevice.getCardNum());
+ }
+
+ public boolean isOutputJackConnected() {
+ return nativeOutputJackConnected(mAlsaDevice.getCardNum());
+ }
+
+ /**
+ * Stop the jack detect thread from calling back into UsbAlsaDevice.
+ * This doesn't force the thread to stop (which is deprecated in java and dangerous due to
+ * locking issues), but will cause the thread to exit at the next safe opportunity.
+ */
+ public void pleaseStop() {
+ synchronized (this) {
+ mStopJackDetect = true;
+ }
+ }
+
+ /**
+ * Called by nativeJackDetect each time a jack detect event is reported.
+ * @return false when the jackDetect thread should stop. true otherwise.
+ */
+ public boolean jackDetectCallback() {
+ synchronized (this) {
+ if (mStopJackDetect) {
+ return false;
+ }
+ mAlsaDevice.updateWiredDeviceConnectionState(true);
+ }
+ return true;
+ }
+
+ /**
+ * This will call jackDetectCallback each time it detects a jack detect event.
+ * If jackDetectCallback returns false, this function will return.
+ */
+ public void run() {
+ nativeJackDetect(mAlsaDevice.getCardNum());
+ }
+}
+
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 0c5f8f113adc..2f1c5169362a 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -20,11 +20,9 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.hardware.usb.UsbDevice;
-import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.midi.MidiDeviceInfo;
import android.os.Bundle;
-import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
import android.service.usb.UsbAlsaManagerProto;
@@ -32,7 +30,6 @@ import android.util.Slog;
import com.android.internal.alsa.AlsaCardsParser;
import com.android.internal.util.dump.DualDumpOutputStream;
-import com.android.server.audio.AudioService;
import com.android.server.usb.descriptors.UsbDescriptorParser;
import libcore.io.IoUtils;
@@ -58,6 +55,7 @@ public final class UsbAlsaManager {
// this is needed to map USB devices to ALSA Audio Devices, especially to remove an
// ALSA device when we are notified that its associated USB device has been removed.
private final ArrayList<UsbAlsaDevice> mAlsaDevices = new ArrayList<UsbAlsaDevice>();
+ private UsbAlsaDevice mSelectedDevice;
/**
* List of connected MIDI devices
@@ -78,17 +76,19 @@ public final class UsbAlsaManager {
ServiceManager.getService(Context.AUDIO_SERVICE));
}
- // Notifies AudioService when a device is added or removed
- // audioDevice - the AudioDevice that was added or removed
- // enabled - if true, we're connecting a device (it's arrived), else disconnecting
- private void notifyDeviceState(UsbAlsaDevice alsaDevice, boolean enabled) {
+ /**
+ * Select the AlsaDevice to be used for AudioService.
+ * AlsaDevice.start() notifies AudioService of it's connected state.
+ *
+ * @param alsaDevice The selected UsbAlsaDevice for system USB audio.
+ */
+ private synchronized void selectAlsaDevice(UsbAlsaDevice alsaDevice) {
if (DEBUG) {
- Slog.d(TAG, "notifyDeviceState " + enabled + " " + alsaDevice);
+ Slog.d(TAG, "selectAlsaDevice " + alsaDevice);
}
- if (mAudioService == null) {
- Slog.e(TAG, "no AudioService");
- return;
+ if (mSelectedDevice != null) {
+ deselectAlsaDevice();
}
// FIXME Does not yet handle the case where the setting is changed
@@ -102,40 +102,14 @@ public final class UsbAlsaManager {
return;
}
- int state = (enabled ? 1 : 0);
- int cardNum = alsaDevice.getCardNum();
- int deviceNum = alsaDevice.getDeviceNum();
- if (cardNum < 0 || deviceNum < 0) {
- Slog.e(TAG, "Invalid alsa card or device alsaCard: " + cardNum
- + " alsaDevice: " + deviceNum);
- return;
- }
-
- String address = AudioService.makeAlsaAddressString(cardNum, deviceNum);
- try {
- // Playback Device
- if (alsaDevice.hasPlayback()) {
- int device = alsaDevice.isOutputHeadset()
- ? AudioSystem.DEVICE_OUT_USB_HEADSET
- : AudioSystem.DEVICE_OUT_USB_DEVICE;
- if (DEBUG) {
- Slog.i(TAG, "pre-call device:0x" + Integer.toHexString(device) +
- " addr:" + address + " name:" + alsaDevice.getDeviceName());
- }
- mAudioService.setWiredDeviceConnectionState(
- device, state, address, alsaDevice.getDeviceName(), TAG);
- }
+ mSelectedDevice = alsaDevice;
+ alsaDevice.start();
+ }
- // Capture Device
- if (alsaDevice.hasCapture()) {
- int device = alsaDevice.isInputHeadset()
- ? AudioSystem.DEVICE_IN_USB_HEADSET
- : AudioSystem.DEVICE_IN_USB_DEVICE;
- mAudioService.setWiredDeviceConnectionState(
- device, state, address, alsaDevice.getDeviceName(), TAG);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "RemoteException in setWiredDeviceConnectionState");
+ private synchronized void deselectAlsaDevice() {
+ if (mSelectedDevice != null) {
+ mSelectedDevice.stop();
+ mSelectedDevice = null;
}
}
@@ -168,7 +142,7 @@ public final class UsbAlsaManager {
Slog.d(TAG, " alsaDevice:" + alsaDevice);
}
if (alsaDevice != null) {
- notifyDeviceState(alsaDevice, true /*enabled*/);
+ selectAlsaDevice(alsaDevice);
}
return alsaDevice;
} else {
@@ -202,16 +176,21 @@ public final class UsbAlsaManager {
if (hasInput || hasOutput) {
boolean isInputHeadset = parser.isInputHeadset();
boolean isOutputHeadset = parser.isOutputHeadset();
- UsbAlsaDevice alsaDevice =
- new UsbAlsaDevice(cardRec.getCardNum(), 0 /*device*/, deviceAddress,
- hasOutput, hasInput, isInputHeadset, isOutputHeadset);
- alsaDevice.setDeviceNameAndDescription(
- cardRec.getCardName(), cardRec.getCardDescription());
- mAlsaDevices.add(0, alsaDevice);
- // Select it
+ if (mAudioService == null) {
+ Slog.e(TAG, "no AudioService");
+ return;
+ }
+
+ UsbAlsaDevice alsaDevice =
+ new UsbAlsaDevice(mAudioService, cardRec.getCardNum(), 0 /*device*/,
+ deviceAddress, hasOutput, hasInput,
+ isInputHeadset, isOutputHeadset);
if (alsaDevice != null) {
- notifyDeviceState(alsaDevice, true /*enabled*/);
+ alsaDevice.setDeviceNameAndDescription(
+ cardRec.getCardName(), cardRec.getCardDescription());
+ mAlsaDevices.add(0, alsaDevice);
+ selectAlsaDevice(alsaDevice);
}
}
@@ -256,7 +235,7 @@ public final class UsbAlsaManager {
}
}
- /* package */ void usbDeviceRemoved(String deviceAddress/*UsbDevice usbDevice*/) {
+ /* package */ synchronized void usbDeviceRemoved(String deviceAddress/*UsbDevice usbDevice*/) {
if (DEBUG) {
Slog.d(TAG, "deviceRemoved(" + deviceAddress + ")");
}
@@ -264,13 +243,9 @@ public final class UsbAlsaManager {
// Audio
UsbAlsaDevice alsaDevice = removeAlsaDeviceFromList(deviceAddress);
Slog.i(TAG, "USB Audio Device Removed: " + alsaDevice);
- if (alsaDevice != null) {
- if (alsaDevice.hasPlayback() || alsaDevice.hasCapture()) {
- notifyDeviceState(alsaDevice, false /*enabled*/);
-
- // if there any external devices left, select one of them
- selectDefaultDevice();
- }
+ if (alsaDevice != null && alsaDevice == mSelectedDevice) {
+ deselectAlsaDevice();
+ selectDefaultDevice(); // if there any external devices left, select one of them
}
// MIDI
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 680694732b2d..a7fc470864a5 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -1786,7 +1786,7 @@ public class UsbDeviceManager implements ActivityManagerInternal.ScreenObserver
mGadgetProxy = IUsbGadget.getService();
mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(),
USB_GADGET_HAL_DEATH_COOKIE);
- if (!mCurrentFunctionsApplied) {
+ if (!mCurrentFunctionsApplied && !mCurrentUsbFunctionsRequested) {
setEnabledFunctions(mCurrentFunctions, false);
}
} catch (NoSuchElementException e) {
diff --git a/telecomm/OWNERS b/telecomm/OWNERS
new file mode 100644
index 000000000000..a3bcfb2cbcfa
--- /dev/null
+++ b/telecomm/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+
+tgunn@google.com
+breadley@google.com
+hallliu@google.com
+rgreenwalt@google.com
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 8c18518a6d67..0c92c2000f92 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -425,8 +425,14 @@ public final class Call {
*/
public static final int PROPERTY_ASSISTED_DIALING_USED = 0x00000200;
+ /**
+ * Indicates that the call is an RTT call. Use {@link #getRttCall()} to get the
+ * {@link RttCall} object that is used to send and receive text.
+ */
+ public static final int PROPERTY_RTT = 0x00000400;
+
//******************************************************************************************
- // Next PROPERTY value: 0x00000400
+ // Next PROPERTY value: 0x00000800
//******************************************************************************************
private final String mTelecomCallId;
@@ -1189,6 +1195,23 @@ public final class Call {
return null;
}
}
+
+ /**
+ * Closes the underlying file descriptors
+ * @hide
+ */
+ public void close() {
+ try {
+ mReceiveStream.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ try {
+ mTransmitStream.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
}
/**
@@ -1664,7 +1687,7 @@ public final class Call {
* @return true if there is a connection, false otherwise.
*/
public boolean isRttActive() {
- return mRttCall != null;
+ return mRttCall != null && mDetails.hasProperty(Details.PROPERTY_RTT);
}
/**
@@ -1867,7 +1890,8 @@ public final class Call {
boolean isRttChanged = false;
boolean rttModeChanged = false;
- if (parcelableCall.getParcelableRttCall() != null && parcelableCall.getIsRttCallChanged()) {
+ if (parcelableCall.getIsRttCallChanged()
+ && mDetails.hasProperty(Details.PROPERTY_RTT)) {
ParcelableRttCall parcelableRttCall = parcelableCall.getParcelableRttCall();
InputStreamReader receiveStream = new InputStreamReader(
new ParcelFileDescriptor.AutoCloseInputStream(
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 5fcff18aa5be..024bd303304f 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -29,7 +29,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
-import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
@@ -82,7 +81,7 @@ public abstract class Conference extends Conferenceable {
private int mConnectionProperties;
private String mDisconnectMessage;
private long mConnectTimeMillis = CONNECT_TIME_NOT_SPECIFIED;
- private long mConnectElapsedTimeMillis = CONNECT_TIME_NOT_SPECIFIED;
+ private long mConnectionStartElapsedRealTime = CONNECT_TIME_NOT_SPECIFIED;
private StatusHints mStatusHints;
private Bundle mExtras;
private Set<String> mPreviousExtraKeys;
@@ -584,30 +583,36 @@ public abstract class Conference extends Conferenceable {
}
/**
- * Sets the connection start time of the {@code Conference}. Should be specified in wall-clock
- * time returned by {@link System#currentTimeMillis()}.
+ * Sets the connection start time of the {@code Conference}. This is used in the call log to
+ * indicate the date and time when the conference took place.
+ * <p>
+ * Should be specified in wall-clock time returned by {@link System#currentTimeMillis()}.
* <p>
* When setting the connection time, you should always set the connection elapsed time via
- * {@link #setConnectionElapsedTime(long)}.
+ * {@link #setConnectionStartElapsedRealTime(long)} to ensure the duration is reflected.
*
- * @param connectionTimeMillis The connection time, in milliseconds.
+ * @param connectionTimeMillis The connection time, in milliseconds, as returned by
+ * {@link System#currentTimeMillis()}.
*/
public final void setConnectionTime(long connectionTimeMillis) {
mConnectTimeMillis = connectionTimeMillis;
}
/**
- * Sets the elapsed time since system boot when the {@link Conference} was connected.
- * This is used to determine the duration of the {@link Conference}.
+ * Sets the start time of the {@link Conference} which is the basis for the determining the
+ * duration of the {@link Conference}.
+ * <p>
+ * You should use a value returned by {@link SystemClock#elapsedRealtime()} to ensure that time
+ * zone changes do not impact the conference duration.
* <p>
- * When setting the connection elapsed time, you should always set the connection time via
+ * When setting this, you should also set the connection time via
* {@link #setConnectionTime(long)}.
*
- * @param connectionElapsedTime The connection time, as measured by
+ * @param connectionStartElapsedRealTime The connection time, as measured by
* {@link SystemClock#elapsedRealtime()}.
*/
- public final void setConnectionElapsedTime(long connectionElapsedTime) {
- mConnectElapsedTimeMillis = connectionElapsedTime;
+ public final void setConnectionStartElapsedRealTime(long connectionStartElapsedRealTime) {
+ mConnectionStartElapsedRealTime = connectionStartElapsedRealTime;
}
/**
@@ -642,8 +647,8 @@ public abstract class Conference extends Conferenceable {
* @return The elapsed time at which the {@link Conference} was connected.
* @hide
*/
- public final long getConnectElapsedTime() {
- return mConnectElapsedTimeMillis;
+ public final long getConnectionStartElapsedRealTime() {
+ return mConnectionStartElapsedRealTime;
}
/**
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index d8599e8ca1fa..26a2f1cb8c4f 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -41,6 +41,8 @@ import android.os.SystemClock;
import android.util.ArraySet;
import android.view.Surface;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
@@ -860,18 +862,19 @@ public abstract class Connection extends Conferenceable {
mFdFromInCall = fromInCall;
mFdToInCall = toInCall;
mPipeFromInCall = new InputStreamReader(
- new ParcelFileDescriptor.AutoCloseInputStream(fromInCall));
+ new FileInputStream(fromInCall.getFileDescriptor()));
mPipeToInCall = new OutputStreamWriter(
- new ParcelFileDescriptor.AutoCloseOutputStream(toInCall));
+ new FileOutputStream(toInCall.getFileDescriptor()));
}
/**
* Writes the string {@param input} into the text stream to the UI for this RTT call. Since
* RTT transmits text in real-time, this method should be called as often as text snippets
* are received from the remote user, even if it is only one character.
- *
+ * <p>
* This method is not thread-safe -- calling it from multiple threads simultaneously may
* lead to interleaved text.
+ *
* @param input The message to send to the in-call app.
*/
public void write(String input) throws IOException {
@@ -884,9 +887,10 @@ public abstract class Connection extends Conferenceable {
* Reads a string from the in-call app, blocking if there is no data available. Returns
* {@code null} if the RTT conversation has been terminated and there is no further data
* to read.
- *
+ * <p>
* This method is not thread-safe -- calling it from multiple threads simultaneously may
* lead to interleaved text.
+ *
* @return A string containing text entered by the user, or {@code null} if the
* conversation has been terminated or if there was an error while reading.
*/
@@ -901,6 +905,7 @@ public abstract class Connection extends Conferenceable {
/**
* Non-blocking version of {@link #read()}. Returns {@code null} if there is nothing to
* be read.
+ *
* @return A string containing text entered by the user, or {@code null} if the user has
* not entered any new text yet.
*/
@@ -2299,7 +2304,7 @@ public abstract class Connection extends Conferenceable {
*
* @hide
*/
- public final void setConnectElapsedTimeMillis(long connectElapsedTimeMillis) {
+ public final void setConnectionStartElapsedRealTime(long connectElapsedTimeMillis) {
mConnectElapsedTimeMillis = connectElapsedTimeMillis;
}
@@ -2635,7 +2640,6 @@ public abstract class Connection extends Conferenceable {
* {@link #onStartRtt(RttTextStream)} has succeeded.
*/
public final void sendRttInitiationSuccess() {
- setRttProperty();
mListeners.forEach((l) -> l.onRttInitiationSuccess(Connection.this));
}
@@ -2647,7 +2651,6 @@ public abstract class Connection extends Conferenceable {
* exception of {@link RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}.
*/
public final void sendRttInitiationFailure(int reason) {
- unsetRttProperty();
mListeners.forEach((l) -> l.onRttInitiationFailure(Connection.this, reason));
}
@@ -2656,7 +2659,6 @@ public abstract class Connection extends Conferenceable {
* side of the coll.
*/
public final void sendRttSessionRemotelyTerminated() {
- unsetRttProperty();
mListeners.forEach((l) -> l.onRttSessionRemotelyTerminated(Connection.this));
}
@@ -2956,22 +2958,6 @@ public abstract class Connection extends Conferenceable {
*/
public void handleRttUpgradeResponse(@Nullable RttTextStream rttTextStream) {}
- /**
- * Internal method to set {@link #PROPERTY_IS_RTT}.
- * @hide
- */
- void setRttProperty() {
- setConnectionProperties(getConnectionProperties() | PROPERTY_IS_RTT);
- }
-
- /**
- * Internal method to un-set {@link #PROPERTY_IS_RTT}.
- * @hide
- */
- void unsetRttProperty() {
- setConnectionProperties(getConnectionProperties() & (~PROPERTY_IS_RTT));
- }
-
static String toLogSafePhoneNumber(String number) {
// For unknown number, log empty string.
if (number == null) {
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index 658b4734b0b5..b6e6b0ed8270 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -143,6 +143,8 @@ public final class ConnectionRequest implements Parcelable {
private final boolean mShouldShowIncomingCallUi;
private final ParcelFileDescriptor mRttPipeToInCall;
private final ParcelFileDescriptor mRttPipeFromInCall;
+ // Cached return value of getRttTextStream -- we don't want to wrap it more than once.
+ private Connection.RttTextStream mRttTextStream;
/**
* @param accountHandle The accountHandle which should be used to place the call.
@@ -312,7 +314,10 @@ public final class ConnectionRequest implements Parcelable {
*/
public Connection.RttTextStream getRttTextStream() {
if (isRequestingRtt()) {
- return new Connection.RttTextStream(mRttPipeToInCall, mRttPipeFromInCall);
+ if (mRttTextStream == null) {
+ mRttTextStream = new Connection.RttTextStream(mRttPipeToInCall, mRttPipeFromInCall);
+ }
+ return mRttTextStream;
} else {
return null;
}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 211699ea5940..ffa0c946d006 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -21,7 +21,6 @@ import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -144,6 +143,7 @@ public abstract class ConnectionService extends Service {
private static final String SESSION_HANDOVER_COMPLETE = "CS.hC";
private static final String SESSION_EXTRAS_CHANGED = "CS.oEC";
private static final String SESSION_START_RTT = "CS.+RTT";
+ private static final String SESSION_UPDATE_RTT_PIPES = "CS.uRTT";
private static final String SESSION_STOP_RTT = "CS.-RTT";
private static final String SESSION_RTT_UPGRADE_RESPONSE = "CS.rTRUR";
private static final String SESSION_CONNECTION_SERVICE_FOCUS_LOST = "CS.cSFL";
@@ -1865,7 +1865,6 @@ public abstract class ConnectionService extends Service {
Log.d(this, "stopRtt(%s)", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "stopRtt").onStopRtt();
- findConnectionForAction(callId, "stopRtt").unsetRttProperty();
} else if (mConferenceById.containsKey(callId)) {
Log.w(this, "stopRtt called on a conference.");
}
@@ -2007,7 +2006,7 @@ public abstract class ConnectionService extends Service {
null : conference.getVideoProvider().getInterface(),
conference.getVideoState(),
conference.getConnectTimeMillis(),
- conference.getConnectElapsedTime(),
+ conference.getConnectionStartElapsedRealTime(),
conference.getStatusHints(),
conference.getExtras());
diff --git a/telephony/java/android/telephony/OWNERS b/telephony/OWNERS
index 68dedce89272..6f67bc25f879 100644
--- a/telephony/java/android/telephony/OWNERS
+++ b/telephony/OWNERS
@@ -1,14 +1,14 @@
set noparent
-amitmahajan@google.com
+tgunn@google.com
breadley@google.com
-fionaxu@google.com
-jackyu@google.com
hallliu@google.com
rgreenwalt@google.com
-tgunn@google.com
-jminjie@google.com
mpq@google.com
+amitmahajan@google.com
+fionaxu@google.com
+jackyu@google.com
+jminjie@google.com
+satk@google.com
shuoq@google.com
refuhoo@google.com
-
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index f009fb145fc2..7e86966e2c1b 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -172,7 +172,7 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P
}
/**
- * Get the timing advance value for LTE, as a value between 0..63.
+ * Get the timing advance value for LTE, as a value in range of 0..1282.
* Integer.MAX_VALUE is reported when there is no active RRC
* connection. Refer to 3GPP 36.213 Sec 4.2.3
* @return the LTE timing advance, if available.
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index cb867abb74d4..ec348dfcc047 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1526,7 +1526,9 @@ public class ServiceState implements Parcelable {
*/
@SystemApi
public List<NetworkRegistrationState> getNetworkRegistrationStates() {
- return mNetworkRegistrationStates;
+ synchronized (mNetworkRegistrationStates) {
+ return new ArrayList<>(mNetworkRegistrationStates);
+ }
}
/**
@@ -1539,11 +1541,15 @@ public class ServiceState implements Parcelable {
@SystemApi
public List<NetworkRegistrationState> getNetworkRegistrationStates(int transportType) {
List<NetworkRegistrationState> list = new ArrayList<>();
- for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
- if (networkRegistrationState.getTransportType() == transportType) {
- list.add(networkRegistrationState);
+
+ synchronized (mNetworkRegistrationStates) {
+ for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
+ if (networkRegistrationState.getTransportType() == transportType) {
+ list.add(networkRegistrationState);
+ }
}
}
+
return list;
}
@@ -1557,12 +1563,36 @@ public class ServiceState implements Parcelable {
*/
@SystemApi
public NetworkRegistrationState getNetworkRegistrationStates(int transportType, int domain) {
- for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
- if (networkRegistrationState.getTransportType() == transportType
- && networkRegistrationState.getDomain() == domain) {
- return networkRegistrationState;
+ synchronized (mNetworkRegistrationStates) {
+ for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
+ if (networkRegistrationState.getTransportType() == transportType
+ && networkRegistrationState.getDomain() == domain) {
+ return networkRegistrationState;
+ }
}
}
+
return null;
}
+
+ /**
+ * @hide
+ */
+ public void addNetworkRegistrationState(NetworkRegistrationState regState) {
+ if (regState == null) return;
+
+ synchronized (mNetworkRegistrationStates) {
+ for (int i = 0; i < mNetworkRegistrationStates.size(); i++) {
+ NetworkRegistrationState curRegState = mNetworkRegistrationStates.get(i);
+ if (curRegState.getTransportType() == regState.getTransportType()
+ && curRegState.getDomain() == regState.getDomain()) {
+ mNetworkRegistrationStates.remove(i);
+ break;
+ }
+ }
+
+ mNetworkRegistrationStates.add(regState);
+ }
+ }
+
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 7afd28ce181f..fefc03d785c4 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -53,6 +53,7 @@ import android.telephony.ims.aidl.IImsMmTelFeature;
import android.telephony.ims.aidl.IImsRcsFeature;
import android.telephony.ims.aidl.IImsRegistration;
import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.util.Log;
import com.android.ims.internal.IImsServiceFeatureCallback;
@@ -6410,84 +6411,106 @@ public class TelephonyManager {
return false;
}
- /**
- * Returns the IMS Registration Status
- * @hide
- */
- public boolean isImsRegistered() {
- try {
- ITelephony telephony = getITelephony();
- if (telephony == null)
- return false;
- return telephony.isImsRegistered();
- } catch (RemoteException ex) {
- return false;
- } catch (NullPointerException ex) {
- return false;
- }
- }
-
/**
- * Returns the IMS Registration Status for a particular Subscription ID
+ * Returns the IMS Registration Status for a particular Subscription ID.
*
* @param subId Subscription ID
* @return true if IMS status is registered, false if the IMS status is not registered or a
* RemoteException occurred.
- *
* @hide
*/
public boolean isImsRegistered(int subId) {
+ try {
+ return getITelephony().isImsRegistered(subId);
+ } catch (RemoteException | NullPointerException ex) {
+ return false;
+ }
+ }
+
+ /**
+ * Returns the IMS Registration Status for a particular Subscription ID, which is determined
+ * when the TelephonyManager is created using {@link #createForSubscriptionId(int)}. If an
+ * invalid subscription ID is used during creation, will the default subscription ID will be
+ * used.
+ *
+ * @return true if IMS status is registered, false if the IMS status is not registered or a
+ * RemoteException occurred.
+ * @see SubscriptionManager#getDefaultSubscriptionId()
+ * @hide
+ */
+ public boolean isImsRegistered() {
try {
- return getITelephony().isImsRegisteredForSubscriber(subId);
- } catch (RemoteException ex) {
- return false;
- } catch (NullPointerException ex) {
+ return getITelephony().isImsRegistered(getSubId());
+ } catch (RemoteException | NullPointerException ex) {
return false;
}
}
/**
- * Returns the Status of Volte
+ * The current status of Voice over LTE for the subscription associated with this instance when
+ * it was created using {@link #createForSubscriptionId(int)}. If an invalid subscription ID was
+ * used during creation, the default subscription ID will be used.
+ * @return true if Voice over LTE is available or false if it is unavailable or unknown.
+ * @see SubscriptionManager#getDefaultSubscriptionId()
* @hide
*/
public boolean isVolteAvailable() {
- try {
- return getITelephony().isVolteAvailable();
- } catch (RemoteException ex) {
- return false;
- } catch (NullPointerException ex) {
- return false;
- }
- }
+ try {
+ return getITelephony().isVolteAvailable(getSubId());
+ } catch (RemoteException | NullPointerException ex) {
+ return false;
+ }
+ }
/**
- * Returns the Status of video telephony (VT)
+ * The availability of Video Telephony (VT) for the subscription ID specified when this instance
+ * was created using {@link #createForSubscriptionId(int)}. If an invalid subscription ID was
+ * used during creation, the default subscription ID will be used. To query the
+ * underlying technology that VT is available on, use {@link #getImsRegTechnologyForMmTel}.
+ * @return true if VT is available, or false if it is unavailable or unknown.
* @hide
*/
public boolean isVideoTelephonyAvailable() {
try {
- return getITelephony().isVideoTelephonyAvailable();
- } catch (RemoteException ex) {
- return false;
- } catch (NullPointerException ex) {
+ return getITelephony().isVideoTelephonyAvailable(getSubId());
+ } catch (RemoteException | NullPointerException ex) {
return false;
}
}
/**
- * Returns the Status of Wi-Fi Calling
+ * Returns the Status of Wi-Fi calling (Voice over WiFi) for the subscription ID specified.
+ * @param subId the subscription ID.
+ * @return true if VoWiFi is available, or false if it is unavailable or unknown.
* @hide
*/
public boolean isWifiCallingAvailable() {
try {
- return getITelephony().isWifiCallingAvailable();
- } catch (RemoteException ex) {
- return false;
- } catch (NullPointerException ex) {
+ return getITelephony().isWifiCallingAvailable(getSubId());
+ } catch (RemoteException | NullPointerException ex) {
return false;
}
}
+ /**
+ * The technology that IMS is registered for for the MMTEL feature.
+ * @param subId subscription ID to get IMS registration technology for.
+ * @return The IMS registration technology that IMS is registered to for the MMTEL feature.
+ * Valid return results are:
+ * - {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE} for LTE registration,
+ * - {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN} for IWLAN registration, or
+ * - {@link ImsRegistrationImplBase#REGISTRATION_TECH_NONE} if we are not registered or the
+ * result is unavailable.
+ * @hide
+ */
+ public @ImsRegistrationImplBase.ImsRegistrationTech int getImsRegTechnologyForMmTel() {
+ try {
+ return getITelephony().getImsRegTechnologyForMmTel(getSubId());
+ } catch (RemoteException ex) {
+ return ImsRegistrationImplBase.REGISTRATION_TECH_NONE;
+ }
+ }
+
/**
* Set TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC for the default phone.
*
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index bfdd4533275b..1fdbae9186b7 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -80,7 +80,7 @@ public abstract class ImsFeature {
public static final String EXTRA_PHONE_ID = "android:phone_id";
/**
- * Invalid feature value\
+ * Invalid feature value
* @hide
*/
public static final int FEATURE_INVALID = -1;
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 2b4c059cf69f..02cc82cf56b0 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1123,33 +1123,33 @@ interface ITelephony {
boolean isHearingAidCompatibilitySupported();
/**
- * Get IMS Registration Status
- */
- boolean isImsRegistered();
-
- /**
* Get IMS Registration Status on a particular subid.
*
* @param subId user preferred subId.
*
* @return {@code true} if the IMS status is registered.
*/
- boolean isImsRegisteredForSubscriber(int subId);
+ boolean isImsRegistered(int subId);
/**
- * Returns the Status of Wi-Fi Calling
+ * Returns the Status of Wi-Fi Calling for the subscription id specified.
*/
- boolean isWifiCallingAvailable();
+ boolean isWifiCallingAvailable(int subId);
/**
- * Returns the Status of Volte
+ * Returns the Status of VoLTE for the subscription ID specified.
*/
- boolean isVolteAvailable();
+ boolean isVolteAvailable(int subId);
/**
- * Returns the Status of VT (video telephony)
+ * Returns the Status of VT (video telephony) for the subscription ID specified.
*/
- boolean isVideoTelephonyAvailable();
+ boolean isVideoTelephonyAvailable(int subId);
+
+ /**
+ * Returns the MMTEL IMS registration technology for the subsciption ID specified.
+ */
+ int getImsRegTechnologyForMmTel(int subId);
/**
* Returns the unique device ID of phone, for example, the IMEI for
diff --git a/tests/ActivityManagerPerfTests/README.txt b/tests/ActivityManagerPerfTests/README.txt
index 77e0e90623fa..1040ed169c5b 100644
--- a/tests/ActivityManagerPerfTests/README.txt
+++ b/tests/ActivityManagerPerfTests/README.txt
@@ -1,12 +1,15 @@
ActivityManagerPerfTests
Performance tests for various ActivityManager components, e.g. Services, Broadcasts
+* These are only for tests that don't require a target package to test against
+* Self-contained perf tests should go in frameworks/base/apct-tests/perftests
-Command to run tests (not working yet, atest seems buggy)
-* atest .../frameworks/base/tests/ActivityManagerPerfTests
+Command to run tests
+* atest .../frameworks/base/tests/ActivityManagerPerfTests/tests/
+ * Command currently not working: b/71859981
* m ActivityManagerPerfTests ActivityManagerPerfTestsTestApp && \
- adb install $OUT/data/app/ActivityManagerPerfTests/ActivityManagerPerfTests.apk && \
- adb install $OUT/data/app/ActivityManagerPerfTestsTestApp/ActivityManagerPerfTestsTestApp.apk && \
+ adb install "$OUT"/data/app/ActivityManagerPerfTests/ActivityManagerPerfTests.apk && \
+ adb install "$OUT"/data/app/ActivityManagerPerfTestsTestApp/ActivityManagerPerfTestsTestApp.apk && \
adb shell am instrument -w \
com.android.frameworks.perftests.amtests/android.support.test.runner.AndroidJUnitRunner
@@ -15,20 +18,42 @@ Overview
* For example, the time it takes from sending an Intent to start a Service
to the time the Service runs its callbacks
* System.nanoTime() is monotonic and consistent between processes, so we use that for measuring time
-* To make sure the test app is running, we start an Activity
* If the test app is involved, it will measure the time and send it back to the instrumentation test
- * The time is sent back through a Binder interface in the Intent
+ * The time is sent back through a Binder interface in the Intent with the help of Utils.sendTime()
* Each sent time is tagged with an id since there can be multiple events that send back a time
- * For example, one is sent when the Activity is started, and another could be sent when a
- Broadcast is received
+* Each test will run multiple times to account for variation in test runs
Structure
* tests
* Instrumentation test which runs the various performance tests and reports the results
-
* test-app
* Target package which contains the Services, BroadcastReceivers, etc. to test against
* Sends the time it measures back to the test package
-
* utils
* Utilities that both the instrumentation test and test app can use
+
+Adding tests
+* Example
+ * Look at tests/src/com/android/frameworks/perftests/am/BroadcastPerfTest and
+ test-app/src/com/android/frameworks/perftests/amteststestapp/TestBroadcastReceiver
+ for simple examples using this framework
+* Steps
+ * Add any components you will test against in the target package under
+ test-app/src/com/android/frameworks/perftests/amteststestapp/
+ * Add the test class under tests/src/com/android/frameworks/perftests/am/tests/
+ * The class should extend BasePerfTest
+ * Each test should call runPerfFunction() returning the elapsed time for a single iteration
+ * The test has access to a Context through mContext
+ * If you are measuring the time elapsed of something that either starts or ends in the target
+ package
+ * The target package can report the time it measures through an ITimeReceiverCallback passed
+ through an Intent through Utils.sendTime(intent, "tag")
+ (or however a Binder needs to be passed to the target package)
+ * The instrumentation test can collect that time by calling getReceivedTimeNs("tag") and
+ calculate the elapsed time
+ * Each timestamp sent to the instrumentation test is tagged with a tag since multiple timestamps
+ can be reported in an iteration
+ * If the target package should be running before your test logic starts, add startTargetPackage();
+ at the beginning of the iteration
+* Reporting
+ * Look at go/am-perf for how to add new tests to dashboards and receive notification on regression
diff --git a/tests/ActivityManagerPerfTests/test-app/Android.mk b/tests/ActivityManagerPerfTests/test-app/Android.mk
index b0a5db7a3134..767e899450cf 100644
--- a/tests/ActivityManagerPerfTests/test-app/Android.mk
+++ b/tests/ActivityManagerPerfTests/test-app/Android.mk
@@ -23,6 +23,8 @@ LOCAL_SRC_FILES := \
LOCAL_STATIC_JAVA_LIBRARIES := \
ActivityManagerPerfTestsUtils
+LOCAL_MIN_SDK_VERSION := 25
+
LOCAL_PACKAGE_NAME := ActivityManagerPerfTestsTestApp
include $(BUILD_PACKAGE)
diff --git a/tests/ActivityManagerPerfTests/tests/Android.mk b/tests/ActivityManagerPerfTests/tests/Android.mk
index daf603d6a63f..7597e69a4006 100644
--- a/tests/ActivityManagerPerfTests/tests/Android.mk
+++ b/tests/ActivityManagerPerfTests/tests/Android.mk
@@ -27,6 +27,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
LOCAL_PACKAGE_NAME := ActivityManagerPerfTests
+LOCAL_MIN_SDK_VERSION := 25
+
# For android.permission.FORCE_STOP_PACKAGES permission
LOCAL_CERTIFICATE := platform
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 063060f166dc..83354d55b005 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -65,6 +65,7 @@ public class AppLaunch extends InstrumentationTestCase {
private static final int JOIN_TIMEOUT = 10000;
private static final String TAG = AppLaunch.class.getSimpleName();
+
// optional parameter: comma separated list of required account types before proceeding
// with the app launch
private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts";
@@ -73,32 +74,36 @@ public class AppLaunch extends InstrumentationTestCase {
private static final String KEY_LAUNCH_ITERATIONS = "launch_iterations";
private static final String KEY_LAUNCH_ORDER = "launch_order";
private static final String KEY_DROP_CACHE = "drop_cache";
- private static final String KEY_SIMULATE_MAINTANANCE = "simulate_maintanance";
- private static final String KEY_SIMPLEPPERF_CMD = "simpleperf_cmd";
+ private static final String KEY_SIMPLEPERF_CMD = "simpleperf_cmd";
+ private static final String KEY_SIMPLEPERF_APP = "simpleperf_app";
private static final String KEY_TRACE_ITERATIONS = "trace_iterations";
private static final String KEY_LAUNCH_DIRECTORY = "launch_directory";
private static final String KEY_TRACE_DIRECTORY = "trace_directory";
private static final String KEY_TRACE_CATEGORY = "trace_categories";
private static final String KEY_TRACE_BUFFERSIZE = "trace_bufferSize";
private static final String KEY_TRACE_DUMPINTERVAL = "tracedump_interval";
+ private static final String KEY_COMPILER_FILTERS = "compiler_filters";
+
+ private static final String SIMPLEPERF_APP_CMD =
+ "simpleperf --log fatal stat --csv -e cpu-cycles,major-faults --app %s & %s";
private static final String WEARABLE_ACTION_GOOGLE =
"com.google.android.wearable.action.GOOGLE";
- private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 5000; //5s to allow app to idle
- private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; //750ms idle for non initial launches
- private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 5000; //5s between launching apps
+ private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 5000; // 5s to allow app to idle
+ private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; // 750ms idle for non initial launches
+ private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 5000; // 5s between launching apps
private static final String LAUNCH_SUB_DIRECTORY = "launch_logs";
private static final String LAUNCH_FILE = "applaunch.txt";
private static final String TRACE_SUB_DIRECTORY = "atrace_logs";
- private static final String DEFAULT_TRACE_CATEGORIES = "sched,freq,gfx,view,dalvik,webview,"
- + "input,wm,disk,am,wm";
+ private static final String DEFAULT_TRACE_CATEGORIES =
+ "sched,freq,gfx,view,dalvik,webview,input,wm,disk,am,wm";
private static final String DEFAULT_TRACE_BUFFER_SIZE = "20000";
private static final String DEFAULT_TRACE_DUMP_INTERVAL = "10";
- private static final String TRIAL_LAUNCH = "TRAIL_LAUNCH";
+ private static final String TRIAL_LAUNCH = "TRIAL_LAUNCH";
private static final String DELIMITER = ",";
private static final String DROP_CACHE_SCRIPT = "/data/local/tmp/dropCache.sh";
private static final String APP_LAUNCH_CMD = "am start -W -n";
private static final String SUCCESS_MESSAGE = "Status: ok";
- private static final String PROFILE_COMPILE_SUCCESS = "Success";
+ private static final String COMPILE_SUCCESS = "Success";
private static final String THIS_TIME = "ThisTime:";
private static final String LAUNCH_ITERATION = "LAUNCH_ITERATION - %d";
private static final String TRACE_ITERATION = "TRACE_ITERATION-%d";
@@ -106,14 +111,15 @@ public class AppLaunch extends InstrumentationTestCase {
private static final String TRACE_ITERATION_PREFIX = "TRACE_ITERATION";
private static final String LAUNCH_ORDER_CYCLIC = "cyclic";
private static final String LAUNCH_ORDER_SEQUENTIAL = "sequential";
- private static final String SPEED_PROFILE_CMD = "cmd package compile -f -m speed-profile %s";
-
-
+ private static final String COMPILE_CMD = "cmd package compile -f -m %s %s";
+ private static final String SPEED_PROFILE_FILTER = "speed-profile";
+ private static final String VERIFY_FILTER = "verify";
+ private static final String LAUNCH_SCRIPT_NAME = "appLaunch";
private Map<String, Intent> mNameToIntent;
private List<LaunchOrder> mLaunchOrderList = new ArrayList<LaunchOrder>();
private Map<String, String> mNameToResultKey;
- private Map<String, List<Long>> mNameToLaunchTime;
+ private Map<String, Map<String, List<AppLaunchResult>>> mNameToLaunchTime;
private IActivityManager mAm;
private String mSimplePerfCmd = null;
private String mLaunchOrder = null;
@@ -123,12 +129,10 @@ public class AppLaunch extends InstrumentationTestCase {
private String mTraceDirectoryStr = null;
private Bundle mResult = new Bundle();
private Set<String> mRequiredAccounts;
- private boolean mTrailLaunch = true;
- private File mFile = null;
- private FileOutputStream mOutputStream = null;
+ private boolean mTrialLaunch = false;
private BufferedWriter mBufferedWriter = null;
- private boolean mSimulateMaintanance = false;
-
+ private boolean mSimplePerfAppOnly = false;
+ private String[] mCompilerFilters = null;
@Override
protected void setUp() throws Exception {
@@ -142,6 +146,16 @@ public class AppLaunch extends InstrumentationTestCase {
super.tearDown();
}
+ private void addLaunchResult(LaunchOrder launch, AppLaunchResult result) {
+ mNameToLaunchTime.get(launch.getApp()).get(launch.getCompilerFilter()).add(result);
+ }
+
+ private boolean hasFailureOnFirstLaunch(LaunchOrder launch) {
+ List<AppLaunchResult> results =
+ mNameToLaunchTime.get(launch.getApp()).get(launch.getCompilerFilter());
+ return (results.size() > 0) && (results.get(0).mLaunchTime < 0);
+ }
+
public void testMeasureStartUpTime() throws RemoteException, NameNotFoundException,
IOException, InterruptedException {
InstrumentationTestRunner instrumentation =
@@ -149,11 +163,6 @@ public class AppLaunch extends InstrumentationTestCase {
Bundle args = instrumentation.getArguments();
mAm = ActivityManager.getService();
String launchDirectory = args.getString(KEY_LAUNCH_DIRECTORY);
- mTraceDirectoryStr = args.getString(KEY_TRACE_DIRECTORY);
- mDropCache = Boolean.parseBoolean(args.getString(KEY_DROP_CACHE));
- mSimplePerfCmd = args.getString(KEY_SIMPLEPPERF_CMD);
- mLaunchOrder = args.getString(KEY_LAUNCH_ORDER, LAUNCH_ORDER_CYCLIC);
- mSimulateMaintanance = Boolean.parseBoolean(args.getString(KEY_SIMULATE_MAINTANANCE));
createMappings();
parseArgs(args);
@@ -171,13 +180,14 @@ public class AppLaunch extends InstrumentationTestCase {
try {
File launchSubDir = new File(launchRootDir, LAUNCH_SUB_DIRECTORY);
+
if (!launchSubDir.exists() && !launchSubDir.mkdirs()) {
throw new IOException("Unable to create the lauch file sub directory");
}
- mFile = new File(launchSubDir, LAUNCH_FILE);
- mOutputStream = new FileOutputStream(mFile);
+ File file = new File(launchSubDir, LAUNCH_FILE);
+ FileOutputStream outputStream = new FileOutputStream(file);
mBufferedWriter = new BufferedWriter(new OutputStreamWriter(
- mOutputStream));
+ outputStream));
// Root directory for trace file during the launches
File rootTrace = null;
@@ -217,70 +227,67 @@ public class AppLaunch extends InstrumentationTestCase {
setLaunchOrder();
for (LaunchOrder launch : mLaunchOrderList) {
+ dropCache();
// App launch times for trial launch will not be used for final
// launch time calculations.
if (launch.getLaunchReason().equals(TRIAL_LAUNCH)) {
// In the "applaunch.txt" file, trail launches is referenced using
// "TRIAL_LAUNCH"
- long launchTime = startApp(launch.getApp(), true, launch.getLaunchReason());
- if (launchTime < 0) {
- List<Long> appLaunchList = new ArrayList<Long>();
- appLaunchList.add(-1L);
- mNameToLaunchTime.put(launch.getApp(), appLaunchList);
+ String appPkgName = mNameToIntent.get(launch.getApp())
+ .getComponent().getPackageName();
+ if (SPEED_PROFILE_FILTER.equals(launch.getCompilerFilter())) {
+ assertTrue(String.format("Not able to compile the app : %s", appPkgName),
+ compileApp(VERIFY_FILTER, appPkgName));
+ } else if (launch.getCompilerFilter() != null) {
+ assertTrue(String.format("Not able to compile the app : %s", appPkgName),
+ compileApp(launch.getCompilerFilter(), appPkgName));
+ }
+ // We only need to run a trial for the speed-profile filter, but we always
+ // run one for "applaunch.txt" consistency.
+ AppLaunchResult launchResult =
+ startApp(launch.getApp(), true, launch.getLaunchReason());
+ if (launchResult.mLaunchTime < 0) {
+ addLaunchResult(launch, new AppLaunchResult());
// simply pass the app if launch isn't successful
// error should have already been logged by startApp
continue;
}
sleep(INITIAL_LAUNCH_IDLE_TIMEOUT);
- closeApp(launch.getApp(), true);
- dropCache();
- if (mSimulateMaintanance) {
- String appPkgName = mNameToIntent.get(launch.getApp())
- .getComponent().getPackageName();
- assertTrue(String.format("Not able to speed profile the app : %s",
- appPkgName), profileCompileApp(appPkgName));
+ if (SPEED_PROFILE_FILTER.equals(launch.getCompilerFilter())) {
+ // Send SIGUSR1 to force dumping a profile.
+ String sendSignalCommand =
+ String.format("killall -s SIGUSR1 %s", appPkgName);
+ getInstrumentation().getUiAutomation().executeShellCommand(
+ sendSignalCommand);
+ assertTrue(String.format("Not able to compile the app : %s", appPkgName),
+ compileApp(launch.getCompilerFilter(), appPkgName));
}
- sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
}
// App launch times used for final calculation
- if (launch.getLaunchReason().contains(LAUNCH_ITERATION_PREFIX)) {
- long launchTime = -1;
- if (null != mNameToLaunchTime.get(launch.getApp())) {
- long firstLaunchTime = mNameToLaunchTime.get(launch.getApp()).get(0);
- if (firstLaunchTime < 0) {
- // skip if the app has failures while launched first
- continue;
- }
+ else if (launch.getLaunchReason().contains(LAUNCH_ITERATION_PREFIX)) {
+ AppLaunchResult launchResults = null;
+ if (hasFailureOnFirstLaunch(launch)) {
+ // skip if the app has failures while launched first
+ continue;
}
// In the "applaunch.txt" file app launches are referenced using
// "LAUNCH_ITERATION - ITERATION NUM"
- launchTime = startApp(launch.getApp(), true, launch.getLaunchReason());
- if (launchTime < 0) {
+ launchResults = startApp(launch.getApp(), true, launch.getLaunchReason());
+ if (launchResults.mLaunchTime < 0) {
+ addLaunchResult(launch, new AppLaunchResult());
// if it fails once, skip the rest of the launches
- List<Long> appLaunchList = new ArrayList<Long>();
- appLaunchList.add(-1L);
- mNameToLaunchTime.put(launch.getApp(), appLaunchList);
continue;
} else {
- if (null != mNameToLaunchTime.get(launch.getApp())) {
- mNameToLaunchTime.get(launch.getApp()).add(launchTime);
- } else {
- List<Long> appLaunchList = new ArrayList<Long>();
- appLaunchList.add(launchTime);
- mNameToLaunchTime.put(launch.getApp(), appLaunchList);
- }
+ addLaunchResult(launch, launchResults);
}
sleep(POST_LAUNCH_IDLE_TIMEOUT);
- closeApp(launch.getApp(), true);
- dropCache();
- sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
}
// App launch times for trace launch will not be used for final
// launch time calculations.
- if (launch.getLaunchReason().contains(TRACE_ITERATION_PREFIX)) {
+ else if (launch.getLaunchReason().contains(TRACE_ITERATION_PREFIX)) {
AtraceLogger atraceLogger = AtraceLogger
.getAtraceLoggerInstance(getInstrumentation());
// Start the trace
@@ -293,11 +300,10 @@ public class AppLaunch extends InstrumentationTestCase {
} finally {
// Stop the trace
atraceLogger.atraceStop();
- closeApp(launch.getApp(), true);
- dropCache();
- sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
}
}
+ closeApp(launch.getApp());
+ sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
}
} finally {
if (null != mBufferedWriter) {
@@ -306,29 +312,45 @@ public class AppLaunch extends InstrumentationTestCase {
}
for (String app : mNameToResultKey.keySet()) {
- StringBuilder launchTimes = new StringBuilder();
- for (Long launch : mNameToLaunchTime.get(app)) {
- launchTimes.append(launch);
- launchTimes.append(",");
+ for (String compilerFilter : mCompilerFilters) {
+ StringBuilder launchTimes = new StringBuilder();
+ StringBuilder cpuCycles = new StringBuilder();
+ StringBuilder majorFaults = new StringBuilder();
+ for (AppLaunchResult result : mNameToLaunchTime.get(app).get(compilerFilter)) {
+ launchTimes.append(result.mLaunchTime);
+ launchTimes.append(",");
+ if (mSimplePerfAppOnly) {
+ cpuCycles.append(result.mCpuCycles);
+ cpuCycles.append(",");
+ majorFaults.append(result.mMajorFaults);
+ majorFaults.append(",");
+ }
+ }
+ String filterName = (compilerFilter == null) ? "" : ("-" + compilerFilter);
+ mResult.putString(mNameToResultKey.get(app) + filterName, launchTimes.toString());
+ if (mSimplePerfAppOnly) {
+ mResult.putString(mNameToResultKey.get(app) + filterName + "-cpuCycles",
+ cpuCycles.toString());
+ mResult.putString(mNameToResultKey.get(app) + filterName + "-majorFaults",
+ majorFaults.toString());
+ }
}
- mResult.putString(mNameToResultKey.get(app), launchTimes.toString());
}
instrumentation.sendStatus(0, mResult);
}
/**
- * Compile the app package using speed compile command and return true or false
+ * Compile the app package using compilerFilter and return true or false
* based on status of the compilation command.
*/
- private boolean profileCompileApp(String appPkgName) throws IOException {
- Log.i(TAG, "Starting to speed profile " + appPkgName);
+ private boolean compileApp(String compilerFilter, String appPkgName) throws IOException {
try (ParcelFileDescriptor result = getInstrumentation().getUiAutomation().
- executeShellCommand(String.format(SPEED_PROFILE_CMD, appPkgName));
+ executeShellCommand(String.format(COMPILE_CMD, compilerFilter, appPkgName));
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
new FileInputStream(result.getFileDescriptor())))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
- if (line.contains(PROFILE_COMPILE_SUCCESS)) {
+ if (line.contains(COMPILE_SUCCESS)) {
return true;
}
}
@@ -344,38 +366,42 @@ public class AppLaunch extends InstrumentationTestCase {
*/
private void setLaunchOrder() {
if (LAUNCH_ORDER_CYCLIC.equalsIgnoreCase(mLaunchOrder)) {
- if (mTrailLaunch) {
- for (String app : mNameToResultKey.keySet()) {
- mLaunchOrderList.add(new LaunchOrder(app, TRIAL_LAUNCH));
- }
- }
- for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
- for (String app : mNameToResultKey.keySet()) {
- mLaunchOrderList.add(new LaunchOrder(app,
- String.format(LAUNCH_ITERATION, launchCount)));
- }
- }
- if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
- for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
+ for (String compilerFilter : mCompilerFilters) {
+ if (mTrialLaunch) {
for (String app : mNameToResultKey.keySet()) {
- mLaunchOrderList.add(new LaunchOrder(app,
- String.format(TRACE_ITERATION, traceCount)));
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH));
}
}
- }
- } else if (LAUNCH_ORDER_SEQUENTIAL.equalsIgnoreCase(mLaunchOrder)) {
- for (String app : mNameToResultKey.keySet()) {
- if (mTrailLaunch) {
- mLaunchOrderList.add(new LaunchOrder(app, TRIAL_LAUNCH));
- }
for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
- mLaunchOrderList.add(new LaunchOrder(app,
- String.format(LAUNCH_ITERATION, launchCount)));
+ for (String app : mNameToResultKey.keySet()) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
+ String.format(LAUNCH_ITERATION, launchCount)));
+ }
}
if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
- mLaunchOrderList.add(new LaunchOrder(app,
- String.format(TRACE_ITERATION, traceCount)));
+ for (String app : mNameToResultKey.keySet()) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
+ String.format(TRACE_ITERATION, traceCount)));
+ }
+ }
+ }
+ }
+ } else if (LAUNCH_ORDER_SEQUENTIAL.equalsIgnoreCase(mLaunchOrder)) {
+ for (String compilerFilter : mCompilerFilters) {
+ for (String app : mNameToResultKey.keySet()) {
+ if (mTrialLaunch) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH));
+ }
+ for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
+ String.format(LAUNCH_ITERATION, launchCount)));
+ }
+ if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
+ for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
+ String.format(TRACE_ITERATION, traceCount)));
+ }
}
}
}
@@ -385,7 +411,7 @@ public class AppLaunch extends InstrumentationTestCase {
}
private void dropCache() {
- if (true == mDropCache) {
+ if (mDropCache) {
assertNotNull("Issue in dropping the cache",
getInstrumentation().getUiAutomation()
.executeShellCommand(DROP_CACHE_SCRIPT));
@@ -394,7 +420,7 @@ public class AppLaunch extends InstrumentationTestCase {
private void parseArgs(Bundle args) {
mNameToResultKey = new LinkedHashMap<String, String>();
- mNameToLaunchTime = new HashMap<String, List<Long>>();
+ mNameToLaunchTime = new HashMap<>();
String launchIterations = args.getString(KEY_LAUNCH_ITERATIONS);
if (launchIterations != null) {
mLaunchIterations = Integer.parseInt(launchIterations);
@@ -421,7 +447,38 @@ public class AppLaunch extends InstrumentationTestCase {
mRequiredAccounts.add(accountType);
}
}
- mTrailLaunch = "true".equals(args.getString(KEY_TRIAL_LAUNCH));
+
+ String compilerFilterList = args.getString(KEY_COMPILER_FILTERS);
+ if (compilerFilterList != null) {
+ // If a compiler filter is passed, we make a trial launch to force compilation
+ // of the apps.
+ mTrialLaunch = true;
+ mCompilerFilters = compilerFilterList.split("\\|");
+ } else {
+ // Just pass a null compiler filter to use the current state of the app.
+ mCompilerFilters = new String[1];
+ }
+
+ // Pre-populate the results map to avoid null checks.
+ for (String app : mNameToLaunchTime.keySet()) {
+ HashMap<String, List<AppLaunchResult>> map = new HashMap<>();
+ mNameToLaunchTime.put(app, map);
+ for (String compilerFilter : mCompilerFilters) {
+ map.put(compilerFilter, new ArrayList<>());
+ }
+ }
+
+ mTraceDirectoryStr = args.getString(KEY_TRACE_DIRECTORY);
+ mDropCache = Boolean.parseBoolean(args.getString(KEY_DROP_CACHE));
+ mSimplePerfCmd = args.getString(KEY_SIMPLEPERF_CMD);
+ mLaunchOrder = args.getString(KEY_LAUNCH_ORDER, LAUNCH_ORDER_CYCLIC);
+ mSimplePerfAppOnly = Boolean.parseBoolean(args.getString(KEY_SIMPLEPERF_APP));
+ mTrialLaunch = mTrialLaunch || Boolean.parseBoolean(args.getString(KEY_TRIAL_LAUNCH));
+
+ if (mSimplePerfCmd != null && mSimplePerfAppOnly) {
+ Log.w(TAG, String.format("Passing both %s and %s is not supported, ignoring %s",
+ KEY_SIMPLEPERF_CMD, KEY_SIMPLEPERF_APP));
+ }
}
private boolean hasLeanback(Context context) {
@@ -465,17 +522,17 @@ public class AppLaunch extends InstrumentationTestCase {
}
}
- private long startApp(String appName, boolean forceStopBeforeLaunch, String launchReason)
- throws NameNotFoundException, RemoteException {
+ private AppLaunchResult startApp(String appName, boolean forceStopBeforeLaunch,
+ String launchReason) throws NameNotFoundException, RemoteException {
Log.i(TAG, "Starting " + appName);
Intent startIntent = mNameToIntent.get(appName);
if (startIntent == null) {
Log.w(TAG, "App does not exist: " + appName);
mResult.putString(mNameToResultKey.get(appName), "App does not exist");
- return -1L;
+ return new AppLaunchResult();
}
- AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent, forceStopBeforeLaunch ,
+ AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent, forceStopBeforeLaunch,
launchReason);
Thread t = new Thread(runnable);
t.start();
@@ -518,22 +575,23 @@ public class AppLaunch extends InstrumentationTestCase {
}
}
- private void closeApp(String appName, boolean forceStopApp) {
+ private void startHomeIntent() {
Intent homeIntent = new Intent(Intent.ACTION_MAIN);
homeIntent.addCategory(Intent.CATEGORY_HOME);
homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
getInstrumentation().getContext().startActivity(homeIntent);
sleep(POST_LAUNCH_IDLE_TIMEOUT);
- if (forceStopApp) {
- Intent startIntent = mNameToIntent.get(appName);
- if (startIntent != null) {
- String packageName = startIntent.getComponent().getPackageName();
- try {
- mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
- } catch (RemoteException e) {
- Log.w(TAG, "Error closing app", e);
- }
+ }
+
+ private void closeApp(String appName) {
+ Intent startIntent = mNameToIntent.get(appName);
+ if (startIntent != null) {
+ String packageName = startIntent.getComponent().getPackageName();
+ try {
+ mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error closing app", e);
}
}
}
@@ -569,10 +627,12 @@ public class AppLaunch extends InstrumentationTestCase {
private class LaunchOrder {
private String mApp;
+ private String mCompilerFilter;
private String mLaunchReason;
- LaunchOrder(String app,String launchReason){
+ LaunchOrder(String app, String compilerFilter, String launchReason){
mApp = app;
+ mCompilerFilter = compilerFilter;
mLaunchReason = launchReason;
}
@@ -584,6 +644,10 @@ public class AppLaunch extends InstrumentationTestCase {
mApp = app;
}
+ public String getCompilerFilter() {
+ return mCompilerFilter;
+ }
+
public String getLaunchReason() {
return mLaunchReason;
}
@@ -593,9 +657,31 @@ public class AppLaunch extends InstrumentationTestCase {
}
}
+ private class AppLaunchResult {
+ long mLaunchTime;
+ long mCpuCycles;
+ long mMajorFaults;
+
+ AppLaunchResult() {
+ mLaunchTime = -1L;
+ mCpuCycles = -1L;
+ mMajorFaults = -1L;
+ }
+
+ AppLaunchResult(String launchTime, String cpuCycles, String majorFaults) {
+ try {
+ mLaunchTime = Long.parseLong(launchTime, 10);
+ mCpuCycles = Long.parseLong(cpuCycles, 10);
+ mMajorFaults = Long.parseLong(majorFaults, 10);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Error parsing result", e);
+ }
+ }
+ }
+
private class AppLaunchRunnable implements Runnable {
private Intent mLaunchIntent;
- private Long mResult;
+ private AppLaunchResult mLaunchResult;
private boolean mForceStopBeforeLaunch;
private String mLaunchReason;
@@ -604,14 +690,15 @@ public class AppLaunch extends InstrumentationTestCase {
mLaunchIntent = intent;
mForceStopBeforeLaunch = forceStopBeforeLaunch;
mLaunchReason = launchReason;
- mResult = -1L;
+ mLaunchResult = new AppLaunchResult();
}
- public Long getResult() {
- return mResult;
+ public AppLaunchResult getResult() {
+ return mLaunchResult;
}
public void run() {
+ File launchFile = null;
try {
String packageName = mLaunchIntent.getComponent().getPackageName();
String componentName = mLaunchIntent.getComponent().flattenToShortString();
@@ -619,17 +706,38 @@ public class AppLaunch extends InstrumentationTestCase {
mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
}
String launchCmd = String.format("%s %s", APP_LAUNCH_CMD, componentName);
- if (null != mSimplePerfCmd) {
+ if (mSimplePerfAppOnly) {
+ try {
+ // executeShellCommand cannot handle shell specific actions, like '&'.
+ // Therefore, we create a file containing the command and make that
+ // the command to launch.
+ launchFile = File.createTempFile(LAUNCH_SCRIPT_NAME, ".sh");
+ launchFile.setExecutable(true);
+ try (FileOutputStream stream = new FileOutputStream(launchFile);
+ BufferedWriter writer =
+ new BufferedWriter(new OutputStreamWriter(stream))) {
+ String cmd = String.format(SIMPLEPERF_APP_CMD, packageName, launchCmd);
+ writer.write(cmd);
+ }
+ launchCmd = launchFile.getAbsolutePath();
+ } catch (IOException e) {
+ Log.w(TAG, "Error writing the launch command", e);
+ return;
+ }
+ } else if (null != mSimplePerfCmd) {
launchCmd = String.format("%s %s", mSimplePerfCmd, launchCmd);
}
Log.v(TAG, "Final launch cmd:" + launchCmd);
ParcelFileDescriptor parcelDesc = getInstrumentation().getUiAutomation()
.executeShellCommand(launchCmd);
- mResult = Long.parseLong(parseLaunchTimeAndWrite(parcelDesc, String.format
- ("App Launch :%s %s",
- componentName, mLaunchReason)), 10);
+ mLaunchResult = parseLaunchTimeAndWrite(parcelDesc, String.format
+ ("App Launch :%s %s", componentName, mLaunchReason));
} catch (RemoteException e) {
Log.w(TAG, "Error launching app", e);
+ } finally {
+ if (launchFile != null) {
+ launchFile.delete();
+ }
}
}
@@ -639,12 +747,14 @@ public class AppLaunch extends InstrumentationTestCase {
* @param parcelDesc
* @return
*/
- private String parseLaunchTimeAndWrite(ParcelFileDescriptor parcelDesc, String headerInfo) {
+ private AppLaunchResult parseLaunchTimeAndWrite(ParcelFileDescriptor parcelDesc,
+ String headerInfo) {
String launchTime = "-1";
+ String cpuCycles = "-1";
+ String majorFaults = "-1";
boolean launchSuccess = false;
try {
InputStream inputStream = new FileInputStream(parcelDesc.getFileDescriptor());
- StringBuilder appLaunchOuput = new StringBuilder();
/* SAMPLE OUTPUT :
Starting: Intent { cmp=com.google.android.calculator/com.android.calculator2.Calculator }
Status: ok
@@ -653,6 +763,11 @@ public class AppLaunch extends InstrumentationTestCase {
TotalTime: 357
WaitTime: 377
Complete*/
+ /* WITH SIMPLEPERF :
+ Performance counter statistics,
+ 6595722690,cpu-cycles,4.511040,GHz,(100%),
+ 0,major-faults,0.000,/sec,(100%),
+ Total test time,1.462129,seconds,*/
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
inputStream));
String line = null;
@@ -669,6 +784,23 @@ public class AppLaunch extends InstrumentationTestCase {
String launchSplit[] = line.split(":");
launchTime = launchSplit[1].trim();
}
+
+ if (mSimplePerfAppOnly) {
+ // Parse simpleperf output.
+ if (lineCount == 9) {
+ if (!line.contains("cpu-cycles")) {
+ Log.e(TAG, "Error in simpleperf output");
+ } else {
+ cpuCycles = line.split(",")[0].trim();
+ }
+ } else if (lineCount == 10) {
+ if (!line.contains("major-faults")) {
+ Log.e(TAG, "Error in simpleperf output");
+ } else {
+ majorFaults = line.split(",")[0].trim();
+ }
+ }
+ }
mBufferedWriter.write(line);
mBufferedWriter.newLine();
lineCount++;
@@ -678,7 +810,7 @@ public class AppLaunch extends InstrumentationTestCase {
} catch (IOException e) {
Log.w(TAG, "Error writing the launch file", e);
}
- return launchTime;
+ return new AppLaunchResult(launchTime, cpuCycles, majorFaults);
}
}
diff --git a/tests/AppLaunchWear/Android.mk b/tests/AppLaunchWear/Android.mk
new file mode 100644
index 000000000000..ac123e79bcd9
--- /dev/null
+++ b/tests/AppLaunchWear/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := AppLaunchWear
+
+LOCAL_CERTIFICATE := platform
+LOCAL_JAVA_LIBRARIES := android.test.base android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/AppLaunchWear/AndroidManifest.xml b/tests/AppLaunchWear/AndroidManifest.xml
new file mode 100644
index 000000000000..7dfd7bafbaaa
--- /dev/null
+++ b/tests/AppLaunchWear/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.tests.applaunch"
+ android:sharedUserId="android.uid.system" >
+
+ <uses-permission android:name="android.permission.REAL_GET_TASKS" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+ <uses-sdk
+ android:minSdkVersion="22"
+ android:targetSdkVersion="24" />
+
+ <instrumentation android:label="Measure app start up time"
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.tests.applaunch" />
+
+ <application android:label="App Launch Test">
+ <uses-library android:name="android.test.runner" />
+ </application>
+</manifest>
diff --git a/tests/AppLaunchWear/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunchWear/src/com/android/tests/applaunch/AppLaunch.java
new file mode 100644
index 000000000000..f32464bf84c2
--- /dev/null
+++ b/tests/AppLaunchWear/src/com/android/tests/applaunch/AppLaunch.java
@@ -0,0 +1,821 @@
+/*
+ * Copyright (C) 2013 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.tests.applaunch;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.app.ActivityManager;
+import android.app.ActivityManager.ProcessErrorStateInfo;
+import android.app.IActivityManager;
+import android.app.UiAutomation;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.support.test.rule.logging.AtraceLogger;
+import android.test.InstrumentationTestCase;
+import android.test.InstrumentationTestRunner;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+/**
+ * This test is intended to measure the time it takes for the apps to start.
+ * Names of the applications are passed in command line, and the
+ * test starts each application, and reports the start up time in milliseconds.
+ * The instrumentation expects the following key to be passed on the command line:
+ * apps - A list of applications to start and their corresponding result keys
+ * in the following format:
+ * -e apps <app name>^<result key>|<app name>^<result key>
+ */
+public class AppLaunch extends InstrumentationTestCase {
+
+ private static final int JOIN_TIMEOUT = 10000;
+ private static final String TAG = AppLaunch.class.getSimpleName();
+
+ // optional parameter: comma separated list of required account types before proceeding
+ // with the app launch
+ private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts";
+ private static final String KEY_APPS = "apps";
+ private static final String KEY_TRIAL_LAUNCH = "trial_launch";
+ private static final String KEY_LAUNCH_ITERATIONS = "launch_iterations";
+ private static final String KEY_LAUNCH_ORDER = "launch_order";
+ private static final String KEY_DROP_CACHE = "drop_cache";
+ private static final String KEY_SIMPLEPERF_CMD = "simpleperf_cmd";
+ private static final String KEY_SIMPLEPERF_APP = "simpleperf_app";
+ private static final String KEY_TRACE_ITERATIONS = "trace_iterations";
+ private static final String KEY_LAUNCH_DIRECTORY = "launch_directory";
+ private static final String KEY_TRACE_DIRECTORY = "trace_directory";
+ private static final String KEY_TRACE_CATEGORY = "trace_categories";
+ private static final String KEY_TRACE_BUFFERSIZE = "trace_bufferSize";
+ private static final String KEY_TRACE_DUMPINTERVAL = "tracedump_interval";
+ private static final String KEY_COMPILER_FILTERS = "compiler_filters";
+
+ private static final String SIMPLEPERF_APP_CMD =
+ "simpleperf --log fatal stat --csv -e cpu-cycles,major-faults --app %s & %s";
+ private static final String WEARABLE_ACTION_GOOGLE =
+ "com.google.android.wearable.action.GOOGLE";
+ private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 5000; // 5s to allow app to idle
+ private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; // 750ms idle for non initial launches
+ private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 5000; // 5s between launching apps
+ private static final String LAUNCH_SUB_DIRECTORY = "launch_logs";
+ private static final String LAUNCH_FILE = "applaunch.txt";
+ private static final String TRACE_SUB_DIRECTORY = "atrace_logs";
+ private static final String DEFAULT_TRACE_CATEGORIES =
+ "sched,freq,gfx,view,dalvik,webview,input,wm,disk,am,wm";
+ private static final String DEFAULT_TRACE_BUFFER_SIZE = "20000";
+ private static final String DEFAULT_TRACE_DUMP_INTERVAL = "10";
+ private static final String TRIAL_LAUNCH = "TRIAL_LAUNCH";
+ private static final String DELIMITER = ",";
+ private static final String DROP_CACHE_SCRIPT = "/data/local/tmp/dropCache.sh";
+ private static final String APP_LAUNCH_CMD = "am start -W -n";
+ private static final String SUCCESS_MESSAGE = "Status: ok";
+ private static final String COMPILE_SUCCESS = "Success";
+ private static final String THIS_TIME = "ThisTime:";
+ private static final String LAUNCH_ITERATION = "LAUNCH_ITERATION - %d";
+ private static final String TRACE_ITERATION = "TRACE_ITERATION-%d";
+ private static final String LAUNCH_ITERATION_PREFIX = "LAUNCH_ITERATION";
+ private static final String TRACE_ITERATION_PREFIX = "TRACE_ITERATION";
+ private static final String LAUNCH_ORDER_CYCLIC = "cyclic";
+ private static final String LAUNCH_ORDER_SEQUENTIAL = "sequential";
+ private static final String COMPILE_CMD = "cmd package compile -f -m %s %s";
+ private static final String SPEED_PROFILE_FILTER = "speed-profile";
+ private static final String VERIFY_FILTER = "verify";
+ private static final String LAUNCH_SCRIPT_NAME = "appLaunch";
+ private static final String WEARABLE_HOME_PACKAGE = "com.google.android.wearable.app";
+
+ private Map<String, Intent> mNameToIntent;
+ private List<LaunchOrder> mLaunchOrderList = new ArrayList<LaunchOrder>();
+ private Map<String, String> mNameToResultKey;
+ private Map<String, Map<String, List<AppLaunchResult>>> mNameToLaunchTime;
+ private IActivityManager mAm;
+ private String mSimplePerfCmd = null;
+ private String mLaunchOrder = null;
+ private boolean mDropCache = false;
+ private int mLaunchIterations = 10;
+ private int mTraceLaunchCount = 0;
+ private String mTraceDirectoryStr = null;
+ private Bundle mResult = new Bundle();
+ private Set<String> mRequiredAccounts;
+ private boolean mTrialLaunch = false;
+ private BufferedWriter mBufferedWriter = null;
+ private boolean mSimplePerfAppOnly = false;
+ private String[] mCompilerFilters = null;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
+ super.tearDown();
+ }
+
+ private void addLaunchResult(LaunchOrder launch, AppLaunchResult result) {
+ mNameToLaunchTime.get(launch.getApp()).get(launch.getCompilerFilter()).add(result);
+ }
+
+ private boolean hasFailureOnFirstLaunch(LaunchOrder launch) {
+ List<AppLaunchResult> results =
+ mNameToLaunchTime.get(launch.getApp()).get(launch.getCompilerFilter());
+ return (results.size() > 0) && (results.get(0).mLaunchTime < 0);
+ }
+
+ public void testMeasureStartUpTime() throws RemoteException, NameNotFoundException,
+ IOException, InterruptedException {
+ InstrumentationTestRunner instrumentation =
+ (InstrumentationTestRunner)getInstrumentation();
+ Bundle args = instrumentation.getArguments();
+ mAm = ActivityManager.getService();
+ String launchDirectory = args.getString(KEY_LAUNCH_DIRECTORY);
+
+ createMappings();
+ parseArgs(args);
+ checkAccountSignIn();
+
+ // Root directory for applaunch file to log the app launch output
+ // Will be useful in case of simpleperf command is used
+ File launchRootDir = null;
+ if (null != launchDirectory && !launchDirectory.isEmpty()) {
+ launchRootDir = new File(launchDirectory);
+ if (!launchRootDir.exists() && !launchRootDir.mkdirs()) {
+ throw new IOException("Unable to create the destination directory");
+ }
+ }
+
+ try {
+ File launchSubDir = new File(launchRootDir, LAUNCH_SUB_DIRECTORY);
+
+ if (!launchSubDir.exists() && !launchSubDir.mkdirs()) {
+ throw new IOException("Unable to create the lauch file sub directory");
+ }
+ File file = new File(launchSubDir, LAUNCH_FILE);
+ FileOutputStream outputStream = new FileOutputStream(file);
+ mBufferedWriter = new BufferedWriter(new OutputStreamWriter(
+ outputStream));
+
+ // Root directory for trace file during the launches
+ File rootTrace = null;
+ File rootTraceSubDir = null;
+ int traceBufferSize = 0;
+ int traceDumpInterval = 0;
+ Set<String> traceCategoriesSet = null;
+ if (null != mTraceDirectoryStr && !mTraceDirectoryStr.isEmpty()) {
+ rootTrace = new File(mTraceDirectoryStr);
+ if (!rootTrace.exists() && !rootTrace.mkdirs()) {
+ throw new IOException("Unable to create the trace directory");
+ }
+ rootTraceSubDir = new File(rootTrace, TRACE_SUB_DIRECTORY);
+ if (!rootTraceSubDir.exists() && !rootTraceSubDir.mkdirs()) {
+ throw new IOException("Unable to create the trace sub directory");
+ }
+ assertNotNull("Trace iteration parameter is mandatory",
+ args.getString(KEY_TRACE_ITERATIONS));
+ mTraceLaunchCount = Integer.parseInt(args.getString(KEY_TRACE_ITERATIONS));
+ String traceCategoriesStr = args
+ .getString(KEY_TRACE_CATEGORY, DEFAULT_TRACE_CATEGORIES);
+ traceBufferSize = Integer.parseInt(args.getString(KEY_TRACE_BUFFERSIZE,
+ DEFAULT_TRACE_BUFFER_SIZE));
+ traceDumpInterval = Integer.parseInt(args.getString(KEY_TRACE_DUMPINTERVAL,
+ DEFAULT_TRACE_DUMP_INTERVAL));
+ traceCategoriesSet = new HashSet<String>();
+ if (!traceCategoriesStr.isEmpty()) {
+ String[] traceCategoriesSplit = traceCategoriesStr.split(DELIMITER);
+ for (int i = 0; i < traceCategoriesSplit.length; i++) {
+ traceCategoriesSet.add(traceCategoriesSplit[i]);
+ }
+ }
+ }
+
+ // Get the app launch order based on launch order, trial launch,
+ // launch iterations and trace iterations
+ setLaunchOrder();
+
+ for (LaunchOrder launch : mLaunchOrderList) {
+ dropCache();
+ String appPkgName = mNameToIntent.get(launch.getApp())
+ .getComponent().getPackageName();
+
+ // App launch times for trial launch will not be used for final
+ // launch time calculations.
+ if (launch.getLaunchReason().equals(TRIAL_LAUNCH)) {
+ // In the "applaunch.txt" file, trail launches is referenced using
+ // "TRIAL_LAUNCH"
+ if (SPEED_PROFILE_FILTER.equals(launch.getCompilerFilter())) {
+ assertTrue(String.format("Not able to compile the app : %s", appPkgName),
+ compileApp(VERIFY_FILTER, appPkgName));
+ } else if (launch.getCompilerFilter() != null) {
+ assertTrue(String.format("Not able to compile the app : %s", appPkgName),
+ compileApp(launch.getCompilerFilter(), appPkgName));
+ }
+ // We only need to run a trial for the speed-profile filter, but we always
+ // run one for "applaunch.txt" consistency.
+ AppLaunchResult launchResult =
+ startApp(launch.getApp(), true, launch.getLaunchReason());
+ if (launchResult.mLaunchTime < 0) {
+ addLaunchResult(launch, new AppLaunchResult());
+ // simply pass the app if launch isn't successful
+ // error should have already been logged by startApp
+ continue;
+ }
+ sleep(INITIAL_LAUNCH_IDLE_TIMEOUT);
+ if (SPEED_PROFILE_FILTER.equals(launch.getCompilerFilter())) {
+ // Send SIGUSR1 to force dumping a profile.
+ String sendSignalCommand =
+ String.format("killall -s SIGUSR1 %s", appPkgName);
+ getInstrumentation().getUiAutomation().executeShellCommand(
+ sendSignalCommand);
+ assertTrue(String.format("Not able to compile the app : %s", appPkgName),
+ compileApp(launch.getCompilerFilter(), appPkgName));
+ }
+ }
+
+ // App launch times used for final calculation
+ else if (launch.getLaunchReason().contains(LAUNCH_ITERATION_PREFIX)) {
+ AppLaunchResult launchResults = null;
+ if (hasFailureOnFirstLaunch(launch)) {
+ // skip if the app has failures while launched first
+ continue;
+ }
+ // In the "applaunch.txt" file app launches are referenced using
+ // "LAUNCH_ITERATION - ITERATION NUM"
+ if (appPkgName.contains(WEARABLE_HOME_PACKAGE)) {
+ launchResults = startApp(launch.getApp(), false, launch.getLaunchReason());
+ } else {
+ launchResults = startApp(launch.getApp(), true, launch.getLaunchReason());
+ }
+ if (launchResults.mLaunchTime < 0) {
+ addLaunchResult(launch, new AppLaunchResult());
+ // if it fails once, skip the rest of the launches
+ continue;
+ } else {
+ addLaunchResult(launch, launchResults);
+ }
+ sleep(POST_LAUNCH_IDLE_TIMEOUT);
+ }
+
+ // App launch times for trace launch will not be used for final
+ // launch time calculations.
+ else if (launch.getLaunchReason().contains(TRACE_ITERATION_PREFIX)) {
+ AtraceLogger atraceLogger = AtraceLogger
+ .getAtraceLoggerInstance(getInstrumentation());
+ // Start the trace
+ try {
+ atraceLogger.atraceStart(traceCategoriesSet, traceBufferSize,
+ traceDumpInterval, rootTraceSubDir,
+ String.format("%s-%s", launch.getApp(), launch.getLaunchReason()));
+ startApp(launch.getApp(), true, launch.getLaunchReason());
+ sleep(POST_LAUNCH_IDLE_TIMEOUT);
+ } finally {
+ // Stop the trace
+ atraceLogger.atraceStop();
+ }
+ }
+ closeApp(launch.getApp(), true);
+ sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
+ }
+ } finally {
+ if (null != mBufferedWriter) {
+ mBufferedWriter.close();
+ }
+ }
+
+ for (String app : mNameToResultKey.keySet()) {
+ for (String compilerFilter : mCompilerFilters) {
+ StringBuilder launchTimes = new StringBuilder();
+ StringBuilder cpuCycles = new StringBuilder();
+ StringBuilder majorFaults = new StringBuilder();
+ for (AppLaunchResult result : mNameToLaunchTime.get(app).get(compilerFilter)) {
+ launchTimes.append(result.mLaunchTime);
+ launchTimes.append(",");
+ if (mSimplePerfAppOnly) {
+ cpuCycles.append(result.mCpuCycles);
+ cpuCycles.append(",");
+ majorFaults.append(result.mMajorFaults);
+ majorFaults.append(",");
+ }
+ }
+ String filterName = (compilerFilter == null) ? "" : ("-" + compilerFilter);
+ mResult.putString(mNameToResultKey.get(app) + filterName, launchTimes.toString());
+ if (mSimplePerfAppOnly) {
+ mResult.putString(mNameToResultKey.get(app) + filterName + "-cpuCycles",
+ cpuCycles.toString());
+ mResult.putString(mNameToResultKey.get(app) + filterName + "-majorFaults",
+ majorFaults.toString());
+ }
+ }
+ }
+ instrumentation.sendStatus(0, mResult);
+ }
+
+ /**
+ * Compile the app package using compilerFilter and return true or false
+ * based on status of the compilation command.
+ */
+ private boolean compileApp(String compilerFilter, String appPkgName) throws IOException {
+ try (ParcelFileDescriptor result = getInstrumentation().getUiAutomation().
+ executeShellCommand(String.format(COMPILE_CMD, compilerFilter, appPkgName));
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
+ new FileInputStream(result.getFileDescriptor())))) {
+ String line;
+ while ((line = bufferedReader.readLine()) != null) {
+ if (line.contains(COMPILE_SUCCESS)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * If launch order is "cyclic" then apps will be launched one after the
+ * other for each iteration count.
+ * If launch order is "sequential" then each app will be launched for given number
+ * iterations at once before launching the other apps.
+ */
+ private void setLaunchOrder() {
+ if (LAUNCH_ORDER_CYCLIC.equalsIgnoreCase(mLaunchOrder)) {
+ for (String compilerFilter : mCompilerFilters) {
+ if (mTrialLaunch) {
+ for (String app : mNameToResultKey.keySet()) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH));
+ }
+ }
+ for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
+ for (String app : mNameToResultKey.keySet()) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
+ String.format(LAUNCH_ITERATION, launchCount)));
+ }
+ }
+ if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
+ for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
+ for (String app : mNameToResultKey.keySet()) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
+ String.format(TRACE_ITERATION, traceCount)));
+ }
+ }
+ }
+ }
+ } else if (LAUNCH_ORDER_SEQUENTIAL.equalsIgnoreCase(mLaunchOrder)) {
+ for (String compilerFilter : mCompilerFilters) {
+ for (String app : mNameToResultKey.keySet()) {
+ if (mTrialLaunch) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH));
+ }
+ for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
+ String.format(LAUNCH_ITERATION, launchCount)));
+ }
+ if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
+ for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
+ String.format(TRACE_ITERATION, traceCount)));
+ }
+ }
+ }
+ }
+ } else {
+ assertTrue("Launch order is not valid parameter", false);
+ }
+ }
+
+ private void dropCache() {
+ if (mDropCache) {
+ assertNotNull("Issue in dropping the cache",
+ getInstrumentation().getUiAutomation()
+ .executeShellCommand(DROP_CACHE_SCRIPT));
+ }
+ }
+
+ private void parseArgs(Bundle args) {
+ mNameToResultKey = new LinkedHashMap<String, String>();
+ mNameToLaunchTime = new HashMap<>();
+ String launchIterations = args.getString(KEY_LAUNCH_ITERATIONS);
+ if (launchIterations != null) {
+ mLaunchIterations = Integer.parseInt(launchIterations);
+ }
+ String appList = args.getString(KEY_APPS);
+ if (appList == null)
+ return;
+
+ String appNames[] = appList.split("\\|");
+ for (String pair : appNames) {
+ String[] parts = pair.split("\\^");
+ if (parts.length != 2) {
+ Log.e(TAG, "The apps key is incorrectly formatted");
+ fail();
+ }
+
+ mNameToResultKey.put(parts[0], parts[1]);
+ mNameToLaunchTime.put(parts[0], null);
+ }
+ String requiredAccounts = args.getString(KEY_REQUIRED_ACCOUNTS);
+ if (requiredAccounts != null) {
+ mRequiredAccounts = new HashSet<String>();
+ for (String accountType : requiredAccounts.split(",")) {
+ mRequiredAccounts.add(accountType);
+ }
+ }
+
+ String compilerFilterList = args.getString(KEY_COMPILER_FILTERS);
+ if (compilerFilterList != null) {
+ // If a compiler filter is passed, we make a trial launch to force compilation
+ // of the apps.
+ mTrialLaunch = true;
+ mCompilerFilters = compilerFilterList.split("\\|");
+ } else {
+ // Just pass a null compiler filter to use the current state of the app.
+ mCompilerFilters = new String[1];
+ }
+
+ // Pre-populate the results map to avoid null checks.
+ for (String app : mNameToLaunchTime.keySet()) {
+ HashMap<String, List<AppLaunchResult>> map = new HashMap<>();
+ mNameToLaunchTime.put(app, map);
+ for (String compilerFilter : mCompilerFilters) {
+ map.put(compilerFilter, new ArrayList<>());
+ }
+ }
+
+ mTraceDirectoryStr = args.getString(KEY_TRACE_DIRECTORY);
+ mDropCache = Boolean.parseBoolean(args.getString(KEY_DROP_CACHE));
+ mSimplePerfCmd = args.getString(KEY_SIMPLEPERF_CMD);
+ mLaunchOrder = args.getString(KEY_LAUNCH_ORDER, LAUNCH_ORDER_CYCLIC);
+ mSimplePerfAppOnly = Boolean.parseBoolean(args.getString(KEY_SIMPLEPERF_APP));
+ mTrialLaunch = mTrialLaunch || Boolean.parseBoolean(args.getString(KEY_TRIAL_LAUNCH));
+
+ if (mSimplePerfCmd != null && mSimplePerfAppOnly) {
+ Log.w(TAG, String.format("Passing both %s and %s is not supported, ignoring %s",
+ KEY_SIMPLEPERF_CMD, KEY_SIMPLEPERF_APP));
+ }
+ }
+
+ private boolean hasLeanback(Context context) {
+ return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ }
+
+ private void createMappings() {
+ mNameToIntent = new LinkedHashMap<String, Intent>();
+
+ PackageManager pm = getInstrumentation().getContext()
+ .getPackageManager();
+ Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
+ intentToResolve.addCategory(hasLeanback(getInstrumentation().getContext()) ?
+ Intent.CATEGORY_LEANBACK_LAUNCHER :
+ Intent.CATEGORY_LAUNCHER);
+ List<ResolveInfo> ris = pm.queryIntentActivities(intentToResolve, 0);
+ resolveLoop(ris, intentToResolve, pm);
+ // For Wear
+ intentToResolve = new Intent(WEARABLE_ACTION_GOOGLE);
+ ris = pm.queryIntentActivities(intentToResolve, 0);
+ resolveLoop(ris, intentToResolve, pm);
+ }
+
+ private void resolveLoop(List<ResolveInfo> ris, Intent intentToResolve, PackageManager pm) {
+ if (ris == null || ris.isEmpty()) {
+ Log.i(TAG, "Could not find any apps");
+ } else {
+ for (ResolveInfo ri : ris) {
+ Intent startIntent = new Intent(intentToResolve);
+ startIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ startIntent.setClassName(ri.activityInfo.packageName,
+ ri.activityInfo.name);
+ String appName = ri.loadLabel(pm).toString();
+ if (appName != null) {
+ // Support launching intent using package name or app name
+ mNameToIntent.put(ri.activityInfo.packageName, startIntent);
+ mNameToIntent.put(appName, startIntent);
+ }
+ }
+ }
+ }
+
+ private AppLaunchResult startApp(String appName, boolean forceStopBeforeLaunch,
+ String launchReason) throws NameNotFoundException, RemoteException {
+ Log.i(TAG, "Starting " + appName);
+
+ Intent startIntent = mNameToIntent.get(appName);
+ if (startIntent == null) {
+ Log.w(TAG, "App does not exist: " + appName);
+ mResult.putString(mNameToResultKey.get(appName), "App does not exist");
+ return new AppLaunchResult();
+ }
+ AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent, forceStopBeforeLaunch,
+ launchReason);
+ Thread t = new Thread(runnable);
+ t.start();
+ try {
+ t.join(JOIN_TIMEOUT);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ return runnable.getResult();
+ }
+
+ private void checkAccountSignIn() {
+ // ensure that the device has the required account types before starting test
+ // e.g. device must have a valid Google account sign in to measure a meaningful launch time
+ // for Gmail
+ if (mRequiredAccounts == null || mRequiredAccounts.isEmpty()) {
+ return;
+ }
+ final AccountManager am =
+ (AccountManager) getInstrumentation().getTargetContext().getSystemService(
+ Context.ACCOUNT_SERVICE);
+ Account[] accounts = am.getAccounts();
+ // use set here in case device has multiple accounts of the same type
+ Set<String> foundAccounts = new HashSet<String>();
+ for (Account account : accounts) {
+ if (mRequiredAccounts.contains(account.type)) {
+ foundAccounts.add(account.type);
+ }
+ }
+ // check if account type matches, if not, fail test with message on what account types
+ // are missing
+ if (mRequiredAccounts.size() != foundAccounts.size()) {
+ mRequiredAccounts.removeAll(foundAccounts);
+ StringBuilder sb = new StringBuilder("Device missing these accounts:");
+ for (String account : mRequiredAccounts) {
+ sb.append(' ');
+ sb.append(account);
+ }
+ fail(sb.toString());
+ }
+ }
+
+ private void closeApp(String appName, boolean forceStopApp) {
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN);
+ homeIntent.addCategory(Intent.CATEGORY_HOME);
+ homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ getInstrumentation().getContext().startActivity(homeIntent);
+ sleep(POST_LAUNCH_IDLE_TIMEOUT);
+ if (forceStopApp) {
+ Intent startIntent = mNameToIntent.get(appName);
+ if (startIntent != null) {
+ String packageName = startIntent.getComponent().getPackageName();
+ try {
+ mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error closing app", e);
+ }
+ }
+ }
+ }
+
+ private void sleep(int time) {
+ try {
+ Thread.sleep(time);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+
+ private void reportError(String appName, String processName) {
+ ActivityManager am = (ActivityManager) getInstrumentation()
+ .getContext().getSystemService(Context.ACTIVITY_SERVICE);
+ List<ProcessErrorStateInfo> crashes = am.getProcessesInErrorState();
+ if (crashes != null) {
+ for (ProcessErrorStateInfo crash : crashes) {
+ if (!crash.processName.equals(processName))
+ continue;
+
+ Log.w(TAG, appName + " crashed: " + crash.shortMsg);
+ mResult.putString(mNameToResultKey.get(appName), crash.shortMsg);
+ return;
+ }
+ }
+
+ mResult.putString(mNameToResultKey.get(appName),
+ "Crashed for unknown reason");
+ Log.w(TAG, appName
+ + " not found in process list, most likely it is crashed");
+ }
+
+ private class LaunchOrder {
+ private String mApp;
+ private String mCompilerFilter;
+ private String mLaunchReason;
+
+ LaunchOrder(String app, String compilerFilter, String launchReason){
+ mApp = app;
+ mCompilerFilter = compilerFilter;
+ mLaunchReason = launchReason;
+ }
+
+ public String getApp() {
+ return mApp;
+ }
+
+ public void setApp(String app) {
+ mApp = app;
+ }
+
+ public String getCompilerFilter() {
+ return mCompilerFilter;
+ }
+
+ public String getLaunchReason() {
+ return mLaunchReason;
+ }
+
+ public void setLaunchReason(String launchReason) {
+ mLaunchReason = launchReason;
+ }
+ }
+
+ private class AppLaunchResult {
+ long mLaunchTime;
+ long mCpuCycles;
+ long mMajorFaults;
+
+ AppLaunchResult() {
+ mLaunchTime = -1L;
+ mCpuCycles = -1L;
+ mMajorFaults = -1L;
+ }
+
+ AppLaunchResult(String launchTime, String cpuCycles, String majorFaults) {
+ try {
+ mLaunchTime = Long.parseLong(launchTime, 10);
+ mCpuCycles = Long.parseLong(cpuCycles, 10);
+ mMajorFaults = Long.parseLong(majorFaults, 10);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Error parsing result", e);
+ }
+ }
+ }
+
+ private class AppLaunchRunnable implements Runnable {
+ private Intent mLaunchIntent;
+ private AppLaunchResult mLaunchResult;
+ private boolean mForceStopBeforeLaunch;
+ private String mLaunchReason;
+
+ public AppLaunchRunnable(Intent intent, boolean forceStopBeforeLaunch,
+ String launchReason) {
+ mLaunchIntent = intent;
+ mForceStopBeforeLaunch = forceStopBeforeLaunch;
+ mLaunchReason = launchReason;
+ mLaunchResult = new AppLaunchResult();
+ }
+
+ public AppLaunchResult getResult() {
+ return mLaunchResult;
+ }
+
+ public void run() {
+ File launchFile = null;
+ try {
+ String packageName = mLaunchIntent.getComponent().getPackageName();
+ String componentName = mLaunchIntent.getComponent().flattenToShortString();
+ if (mForceStopBeforeLaunch) {
+ mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
+ }
+ String launchCmd = String.format("%s %s", APP_LAUNCH_CMD, componentName);
+ if (mSimplePerfAppOnly) {
+ try {
+ // executeShellCommand cannot handle shell specific actions, like '&'.
+ // Therefore, we create a file containing the command and make that
+ // the command to launch.
+ launchFile = File.createTempFile(LAUNCH_SCRIPT_NAME, ".sh");
+ launchFile.setExecutable(true);
+ try (FileOutputStream stream = new FileOutputStream(launchFile);
+ BufferedWriter writer =
+ new BufferedWriter(new OutputStreamWriter(stream))) {
+ String cmd = String.format(SIMPLEPERF_APP_CMD, packageName, launchCmd);
+ writer.write(cmd);
+ }
+ launchCmd = launchFile.getAbsolutePath();
+ } catch (IOException e) {
+ Log.w(TAG, "Error writing the launch command", e);
+ return;
+ }
+ } else if (null != mSimplePerfCmd) {
+ launchCmd = String.format("%s %s", mSimplePerfCmd, launchCmd);
+ }
+ Log.v(TAG, "Final launch cmd:" + launchCmd);
+ ParcelFileDescriptor parcelDesc = getInstrumentation().getUiAutomation()
+ .executeShellCommand(launchCmd);
+ mLaunchResult = parseLaunchTimeAndWrite(parcelDesc, String.format
+ ("App Launch :%s %s", componentName, mLaunchReason));
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error launching app", e);
+ } finally {
+ if (launchFile != null) {
+ launchFile.delete();
+ }
+ }
+ }
+
+ /**
+ * Method to parse the launch time info and write the result to file
+ *
+ * @param parcelDesc
+ * @return
+ */
+ private AppLaunchResult parseLaunchTimeAndWrite(ParcelFileDescriptor parcelDesc,
+ String headerInfo) {
+ String launchTime = "-1";
+ String cpuCycles = "-1";
+ String majorFaults = "-1";
+ boolean launchSuccess = false;
+ try {
+ InputStream inputStream = new FileInputStream(parcelDesc.getFileDescriptor());
+ /* SAMPLE OUTPUT :
+ Starting: Intent { cmp=com.google.android.calculator/com.android.calculator2.Calculator }
+ Status: ok
+ Activity: com.google.android.calculator/com.android.calculator2.Calculator
+ ThisTime: 357
+ TotalTime: 357
+ WaitTime: 377
+ Complete*/
+ /* WITH SIMPLEPERF :
+ Performance counter statistics,
+ 6595722690,cpu-cycles,4.511040,GHz,(100%),
+ 0,major-faults,0.000,/sec,(100%),
+ Total test time,1.462129,seconds,*/
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
+ inputStream));
+ String line = null;
+ int lineCount = 1;
+ mBufferedWriter.newLine();
+ mBufferedWriter.write(headerInfo);
+ mBufferedWriter.newLine();
+ while ((line = bufferedReader.readLine()) != null) {
+ if (lineCount == 2 && line.contains(SUCCESS_MESSAGE)) {
+ launchSuccess = true;
+ }
+ // Parse TotalTime which is the launch time
+ if (launchSuccess && lineCount == 5) {
+ String launchSplit[] = line.split(":");
+ launchTime = launchSplit[1].trim();
+ }
+
+ if (mSimplePerfAppOnly) {
+ // Parse simpleperf output.
+ if (lineCount == 9) {
+ if (!line.contains("cpu-cycles")) {
+ Log.e(TAG, "Error in simpleperf output");
+ } else {
+ cpuCycles = line.split(",")[0].trim();
+ }
+ } else if (lineCount == 10) {
+ if (!line.contains("major-faults")) {
+ Log.e(TAG, "Error in simpleperf output");
+ } else {
+ majorFaults = line.split(",")[0].trim();
+ }
+ }
+ }
+ mBufferedWriter.write(line);
+ mBufferedWriter.newLine();
+ lineCount++;
+ }
+ mBufferedWriter.flush();
+ inputStream.close();
+ } catch (IOException e) {
+ Log.w(TAG, "Error writing the launch file", e);
+ }
+ return new AppLaunchResult(launchTime, cpuCycles, majorFaults);
+ }
+
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/DrawIntoHwBitmapActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/DrawIntoHwBitmapActivity.java
index faabdfc01de7..af8e10bc07ae 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/DrawIntoHwBitmapActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/DrawIntoHwBitmapActivity.java
@@ -27,6 +27,7 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.GraphicBuffer;
import android.graphics.Paint;
+import android.graphics.Picture;
import android.graphics.PixelFormat;
import android.graphics.SurfaceTexture;
import android.os.Bundle;
@@ -47,10 +48,8 @@ public class DrawIntoHwBitmapActivity extends Activity {
}
Bitmap createBitmap() {
- RenderNode node = RenderNode.create("HwuiCanvas", null);
- node.setLeftTopRightBottom(0, 0, 500, 500);
- node.setClipToBounds(false);
- DisplayListCanvas canvas = node.start(500, 500);
+ Picture picture = new Picture();
+ Canvas canvas = picture.beginRecording(500, 500);
Paint p = new Paint();
p.setColor(Color.BLACK);
p.setTextSize(20 * getResources().getDisplayMetrics().density);
@@ -59,7 +58,7 @@ public class DrawIntoHwBitmapActivity extends Activity {
canvas.drawRect(0, 0, 500, 100, p);
p.setColor(Color.BLACK);
canvas.drawText("Hello, World!", 0, 90, p);
- node.end(canvas);
- return ThreadedRenderer.createHardwareBitmap(node, 500, 500);
+ picture.endRecording();
+ return Bitmap.createBitmap(picture);
}
}
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index cc792cc749d9..03a617c354fa 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -38,6 +38,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.timeout;
@@ -217,7 +218,8 @@ public class ConnectivityManagerTest {
// callback triggers
captor.getValue().send(makeMessage(request, ConnectivityManager.CALLBACK_AVAILABLE));
- verify(callback, timeout(500).times(1)).onAvailable(any());
+ verify(callback, timeout(500).times(1)).onAvailable(any(Network.class),
+ any(NetworkCapabilities.class), any(LinkProperties.class));
// unregister callback
manager.unregisterNetworkCallback(callback);
@@ -244,7 +246,8 @@ public class ConnectivityManagerTest {
// callback triggers
captor.getValue().send(makeMessage(req1, ConnectivityManager.CALLBACK_AVAILABLE));
- verify(callback, timeout(100).times(1)).onAvailable(any());
+ verify(callback, timeout(100).times(1)).onAvailable(any(Network.class),
+ any(NetworkCapabilities.class), any(LinkProperties.class));
// unregister callback
manager.unregisterNetworkCallback(callback);
@@ -335,6 +338,10 @@ public class ConnectivityManagerTest {
static Message makeMessage(NetworkRequest req, int messageType) {
Bundle bundle = new Bundle();
bundle.putParcelable(NetworkRequest.class.getSimpleName(), req);
+ // Pass default objects as we don't care which get passed here
+ bundle.putParcelable(Network.class.getSimpleName(), new Network(1));
+ bundle.putParcelable(NetworkCapabilities.class.getSimpleName(), new NetworkCapabilities());
+ bundle.putParcelable(LinkProperties.class.getSimpleName(), new LinkProperties());
Message msg = Message.obtain();
msg.what = messageType;
msg.setData(bundle);
diff --git a/tests/net/java/android/net/IpSecConfigTest.java b/tests/net/java/android/net/IpSecConfigTest.java
index f6c5532363e8..f186ee55d2c7 100644
--- a/tests/net/java/android/net/IpSecConfigTest.java
+++ b/tests/net/java/android/net/IpSecConfigTest.java
@@ -17,6 +17,7 @@
package android.net;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -48,18 +49,12 @@ public class IpSecConfigTest {
assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getSpiResourceId());
}
- @Test
- public void testParcelUnparcel() throws Exception {
- assertParcelingIsLossless(new IpSecConfig());
-
+ private IpSecConfig getSampleConfig() {
IpSecConfig c = new IpSecConfig();
c.setMode(IpSecTransform.MODE_TUNNEL);
c.setSourceAddress("0.0.0.0");
c.setDestinationAddress("1.2.3.4");
- c.setEncapType(android.system.OsConstants.UDP_ENCAP_ESPINUDP);
- c.setEncapSocketResourceId(7);
- c.setEncapRemotePort(22);
- c.setNattKeepaliveInterval(42);
+ c.setSpiResourceId(1984);
c.setEncryption(
new IpSecAlgorithm(
IpSecAlgorithm.CRYPT_AES_CBC,
@@ -68,7 +63,37 @@ public class IpSecConfigTest {
new IpSecAlgorithm(
IpSecAlgorithm.AUTH_HMAC_MD5,
new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0}));
- c.setSpiResourceId(1984);
+ c.setAuthenticatedEncryption(
+ new IpSecAlgorithm(
+ IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
+ new byte[] {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0, 1, 2, 3, 4
+ },
+ 128));
+ c.setEncapType(android.system.OsConstants.UDP_ENCAP_ESPINUDP);
+ c.setEncapSocketResourceId(7);
+ c.setEncapRemotePort(22);
+ c.setNattKeepaliveInterval(42);
+ c.setMarkValue(12);
+ c.setMarkMask(23);
+
+ return c;
+ }
+
+ @Test
+ public void testCopyConstructor() {
+ IpSecConfig original = getSampleConfig();
+ IpSecConfig copy = new IpSecConfig(original);
+
+ assertTrue(IpSecConfig.equals(original, copy));
+ assertFalse(original == copy);
+ }
+
+ @Test
+ public void testParcelUnparcel() throws Exception {
+ assertParcelingIsLossless(new IpSecConfig());
+
+ IpSecConfig c = getSampleConfig();
assertParcelingIsLossless(c);
}
diff --git a/tests/net/java/android/net/IpSecTransformTest.java b/tests/net/java/android/net/IpSecTransformTest.java
new file mode 100644
index 000000000000..ffd1f063e48b
--- /dev/null
+++ b/tests/net/java/android/net/IpSecTransformTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for {@link IpSecTransform}. */
+@SmallTest
+@RunWith(JUnit4.class)
+public class IpSecTransformTest {
+
+ @Test
+ public void testCreateTransformCopiesConfig() {
+ // Create a config with a few parameters to make sure it's not empty
+ IpSecConfig config = new IpSecConfig();
+ config.setSourceAddress("0.0.0.0");
+ config.setDestinationAddress("1.2.3.4");
+ config.setSpiResourceId(1984);
+
+ IpSecTransform preModification = new IpSecTransform(null, config);
+
+ config.setSpiResourceId(1985);
+ IpSecTransform postModification = new IpSecTransform(null, config);
+
+ assertFalse(IpSecTransform.equals(preModification, postModification));
+ }
+
+ @Test
+ public void testCreateTransformsWithSameConfigEqual() {
+ // Create a config with a few parameters to make sure it's not empty
+ IpSecConfig config = new IpSecConfig();
+ config.setSourceAddress("0.0.0.0");
+ config.setDestinationAddress("1.2.3.4");
+ config.setSpiResourceId(1984);
+
+ IpSecTransform config1 = new IpSecTransform(null, config);
+ IpSecTransform config2 = new IpSecTransform(null, config);
+
+ assertTrue(IpSecTransform.equals(config1, config2));
+ }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index e7abede4cda4..24639e9e3f76 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -35,6 +35,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
@@ -528,6 +529,11 @@ public class ConnectivityServiceTest {
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
}
+ public void resume() {
+ mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
+ mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ }
+
public void disconnect() {
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
@@ -569,6 +575,10 @@ public class ConnectivityServiceTest {
assertTrue(mNetworkStatusReceived.block(TIMEOUT_MS));
return mRedirectUrl;
}
+
+ public NetworkCapabilities getNetworkCapabilities() {
+ return mNetworkCapabilities;
+ }
}
/**
@@ -1273,6 +1283,7 @@ public class ConnectivityServiceTest {
NETWORK_CAPABILITIES,
LINK_PROPERTIES,
SUSPENDED,
+ RESUMED,
LOSING,
LOST,
UNAVAILABLE
@@ -1344,6 +1355,11 @@ public class ConnectivityServiceTest {
}
@Override
+ public void onNetworkResumed(Network network) {
+ setLastCallback(CallbackState.RESUMED, network, null);
+ }
+
+ @Override
public void onLosing(Network network, int maxMsToLive) {
setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */);
}
@@ -2459,16 +2475,31 @@ public class ConnectivityServiceTest {
// Suspend the network.
mCellNetworkAgent.suspend();
+ cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_SUSPENDED,
+ mCellNetworkAgent);
cellNetworkCallback.expectCallback(CallbackState.SUSPENDED, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
// Register a garden variety default network request.
- final TestNetworkCallback dfltNetworkCallback = new TestNetworkCallback();
+ TestNetworkCallback dfltNetworkCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(dfltNetworkCallback);
// We should get onAvailable(), onCapabilitiesChanged(), onLinkPropertiesChanged(),
// as well as onNetworkSuspended() in rapid succession.
dfltNetworkCallback.expectAvailableAndSuspendedCallbacks(mCellNetworkAgent, true);
dfltNetworkCallback.assertNoCallback();
+ mCm.unregisterNetworkCallback(dfltNetworkCallback);
+
+ mCellNetworkAgent.resume();
+ cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_SUSPENDED,
+ mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackState.RESUMED, mCellNetworkAgent);
+ cellNetworkCallback.assertNoCallback();
+
+ dfltNetworkCallback = new TestNetworkCallback();
+ mCm.registerDefaultNetworkCallback(dfltNetworkCallback);
+ // This time onNetworkSuspended should not be called.
+ dfltNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ dfltNetworkCallback.assertNoCallback();
mCm.unregisterNetworkCallback(dfltNetworkCallback);
mCm.unregisterNetworkCallback(cellNetworkCallback);
@@ -3682,8 +3713,7 @@ public class ConnectivityServiceTest {
vpnNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
genericNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
- vpnNetworkCallback.expectCapabilitiesLike(
- nc -> nc.appliesToUid(uid) && !nc.appliesToUid(uid + 1), vpnNetworkAgent);
+ vpnNetworkCallback.expectCapabilitiesLike(nc -> null == nc.getUids(), vpnNetworkAgent);
ranges.clear();
vpnNetworkAgent.setUids(ranges);
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 0f26edb28009..b1b05e8b86ba 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -87,12 +87,11 @@ import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.PowerManager;
+import android.os.SimpleClock;
import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import android.telephony.TelephonyManager;
-import android.util.Log;
-import android.util.TrustedTime;
import com.android.internal.net.VpnInfo;
import com.android.internal.util.test.BroadcastInterceptingContext;
@@ -111,6 +110,8 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.io.File;
+import java.time.Clock;
+import java.time.ZoneOffset;
import java.util.Objects;
/**
@@ -155,7 +156,6 @@ public class NetworkStatsServiceTest {
private File mStatsDir;
private @Mock INetworkManagementService mNetManager;
- private @Mock TrustedTime mTime;
private @Mock NetworkStatsSettings mSettings;
private @Mock IConnectivityManager mConnManager;
private @Mock IBinder mBinder;
@@ -167,6 +167,13 @@ public class NetworkStatsServiceTest {
private INetworkStatsSession mSession;
private INetworkManagementEventObserver mNetworkObserver;
+ private final Clock mClock = new SimpleClock(ZoneOffset.UTC) {
+ @Override
+ public long millis() {
+ return currentTimeMillis();
+ }
+ };
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -184,7 +191,7 @@ public class NetworkStatsServiceTest {
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mService = new NetworkStatsService(
- mServiceContext, mNetManager, mAlarmManager, wakeLock, mTime,
+ mServiceContext, mNetManager, mAlarmManager, wakeLock, mClock,
TelephonyManager.getDefault(), mSettings, new NetworkStatsObservers(),
mStatsDir, getBaseDir(mStatsDir));
mHandlerThread = new HandlerThread("HandlerThread");
@@ -196,7 +203,6 @@ public class NetworkStatsServiceTest {
mElapsedRealtime = 0L;
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsUidDetail(buildEmptyStats());
expectSystemReady();
@@ -221,7 +227,6 @@ public class NetworkStatsServiceTest {
mStatsDir = null;
mNetManager = null;
- mTime = null;
mSettings = null;
mConnManager = null;
@@ -233,7 +238,6 @@ public class NetworkStatsServiceTest {
public void testNetworkStatsWifi() throws Exception {
// pretend that wifi network comes online; service should ask about full
// network state, and poll any existing interfaces before updating.
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
@@ -248,7 +252,6 @@ public class NetworkStatsServiceTest {
// modify some number on wifi, and trigger poll event
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 1024L, 1L, 2048L, 2L));
@@ -262,7 +265,6 @@ public class NetworkStatsServiceTest {
// and bump forward again, with counters going higher. this is
// important, since polling should correctly subtract last snapshot.
incrementCurrentTime(DAY_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 4096L, 4L, 8192L, 8L));
@@ -280,7 +282,6 @@ public class NetworkStatsServiceTest {
// pretend that wifi network comes online; service should ask about full
// network state, and poll any existing interfaces before updating.
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
@@ -295,7 +296,6 @@ public class NetworkStatsServiceTest {
// modify some number on wifi, and trigger poll event
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 1024L, 8L, 2048L, 16L));
@@ -324,13 +324,11 @@ public class NetworkStatsServiceTest {
// graceful shutdown system, which should trigger persist of stats, and
// clear any values in memory.
- expectCurrentTime();
expectDefaultSettings();
mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SHUTDOWN));
assertStatsFilesExist(true);
// boot through serviceReady() again
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsUidDetail(buildEmptyStats());
expectSystemReady();
@@ -358,7 +356,6 @@ public class NetworkStatsServiceTest {
// pretend that wifi network comes online; service should ask about full
// network state, and poll any existing interfaces before updating.
- expectCurrentTime();
expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
@@ -370,7 +367,6 @@ public class NetworkStatsServiceTest {
// modify some number on wifi, and trigger poll event
incrementCurrentTime(2 * HOUR_IN_MILLIS);
- expectCurrentTime();
expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 512L, 4L, 512L, 4L));
@@ -386,7 +382,6 @@ public class NetworkStatsServiceTest {
// now change bucket duration setting and trigger another poll with
// exact same values, which should resize existing buckets.
- expectCurrentTime();
expectSettings(0L, 30 * MINUTE_IN_MILLIS, WEEK_IN_MILLIS);
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
@@ -403,7 +398,6 @@ public class NetworkStatsServiceTest {
@Test
public void testUidStatsAcrossNetworks() throws Exception {
// pretend first mobile network comes online
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildMobile3gState(IMSI_1));
expectNetworkStatsSummary(buildEmptyStats());
@@ -415,7 +409,6 @@ public class NetworkStatsServiceTest {
// create some traffic on first network
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L));
@@ -437,7 +430,6 @@ public class NetworkStatsServiceTest {
// now switch networks; this also tests that we're okay with interfaces
// disappearing, to verify we don't count backwards.
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildMobile3gState(IMSI_2));
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
@@ -454,7 +446,6 @@ public class NetworkStatsServiceTest {
// create traffic on second network
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 2176L, 17L, 1536L, 12L));
@@ -483,7 +474,6 @@ public class NetworkStatsServiceTest {
@Test
public void testUidRemovedIsMoved() throws Exception {
// pretend that network comes online
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
@@ -495,7 +485,6 @@ public class NetworkStatsServiceTest {
// create some traffic
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 4128L, 258L, 544L, 34L));
@@ -517,7 +506,6 @@ public class NetworkStatsServiceTest {
// now pretend two UIDs are uninstalled, which should migrate stats to
// special "removed" bucket.
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 4128L, 258L, 544L, 34L));
@@ -545,7 +533,6 @@ public class NetworkStatsServiceTest {
@Test
public void testUid3g4gCombinedByTemplate() throws Exception {
// pretend that network comes online
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildMobile3gState(IMSI_1));
expectNetworkStatsSummary(buildEmptyStats());
@@ -557,7 +544,6 @@ public class NetworkStatsServiceTest {
// create some traffic
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
@@ -573,7 +559,6 @@ public class NetworkStatsServiceTest {
// now switch over to 4g network
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildMobile4gState(TEST_IFACE2));
expectNetworkStatsSummary(buildEmptyStats());
@@ -588,7 +573,6 @@ public class NetworkStatsServiceTest {
// create traffic on second network
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
@@ -607,7 +591,6 @@ public class NetworkStatsServiceTest {
@Test
public void testSummaryForAllUid() throws Exception {
// pretend that network comes online
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
@@ -619,7 +602,6 @@ public class NetworkStatsServiceTest {
// create some traffic for two apps
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
@@ -637,7 +619,6 @@ public class NetworkStatsServiceTest {
// now create more traffic in next hour, but only for one app
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
@@ -669,7 +650,6 @@ public class NetworkStatsServiceTest {
@Test
public void testForegroundBackground() throws Exception {
// pretend that network comes online
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
@@ -681,7 +661,6 @@ public class NetworkStatsServiceTest {
// create some initial traffic
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
@@ -697,7 +676,6 @@ public class NetworkStatsServiceTest {
// now switch to foreground
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
@@ -730,7 +708,6 @@ public class NetworkStatsServiceTest {
@Test
public void testMetered() throws Exception {
// pretend that network comes online
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildWifiState(true /* isMetered */));
expectNetworkStatsSummary(buildEmptyStats());
@@ -742,7 +719,6 @@ public class NetworkStatsServiceTest {
// create some initial traffic
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
// Note that all traffic from NetworkManagementService is tagged as METERED_NO, ROAMING_NO
@@ -772,7 +748,6 @@ public class NetworkStatsServiceTest {
@Test
public void testRoaming() throws Exception {
// pretend that network comes online
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildMobile3gState(IMSI_1, true /* isRoaming */));
expectNetworkStatsSummary(buildEmptyStats());
@@ -784,7 +759,6 @@ public class NetworkStatsServiceTest {
// Create some traffic
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
// Note that all traffic from NetworkManagementService is tagged as METERED_NO and
@@ -813,7 +787,6 @@ public class NetworkStatsServiceTest {
@Test
public void testTethering() throws Exception {
// pretend first mobile network comes online
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildMobile3gState(IMSI_1));
expectNetworkStatsSummary(buildEmptyStats());
@@ -825,7 +798,6 @@ public class NetworkStatsServiceTest {
// create some tethering traffic
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
// Traffic seen by kernel counters (includes software tethering).
@@ -858,7 +830,6 @@ public class NetworkStatsServiceTest {
public void testRegisterUsageCallback() throws Exception {
// pretend that wifi network comes online; service should ask about full
// network state, and poll any existing interfaces before updating.
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
@@ -880,7 +851,6 @@ public class NetworkStatsServiceTest {
Messenger messenger = new Messenger(latchedHandler);
// Force poll
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
@@ -909,7 +879,6 @@ public class NetworkStatsServiceTest {
// modify some number on wifi, and trigger poll event
// not enough traffic to call data usage callback
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 1024L, 1L, 2048L, 2L));
@@ -925,7 +894,6 @@ public class NetworkStatsServiceTest {
// and bump forward again, with counters going higher. this is
// important, since it will trigger the data usage callback
incrementCurrentTime(DAY_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 4096000L, 4L, 8192000L, 8L));
@@ -1068,7 +1036,6 @@ public class NetworkStatsServiceTest {
private void expectSettings(long persistBytes, long bucketDuration, long deleteAge)
throws Exception {
when(mSettings.getPollInterval()).thenReturn(HOUR_IN_MILLIS);
- when(mSettings.getTimeCacheMaxAge()).thenReturn(DAY_IN_MILLIS);
when(mSettings.getSampleEnabled()).thenReturn(true);
final Config config = new Config(bucketDuration, deleteAge, deleteAge);
@@ -1084,14 +1051,6 @@ public class NetworkStatsServiceTest {
when(mSettings.getUidTagPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
}
- private void expectCurrentTime() throws Exception {
- when(mTime.forceRefresh()).thenReturn(false);
- when(mTime.hasCache()).thenReturn(true);
- when(mTime.currentTimeMillis()).thenReturn(currentTimeMillis());
- when(mTime.getCacheAge()).thenReturn(0L);
- when(mTime.getCacheCertainty()).thenReturn(0L);
- }
-
private void expectBandwidthControlCheck() throws Exception {
when(mNetManager.isBandwidthControlEnabled()).thenReturn(true);
}
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 5831875680ac..f064cb14248f 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -414,59 +414,78 @@ class XmlPrinter : public xml::ConstVisitor {
public:
using xml::ConstVisitor::Visit;
- void Visit(const xml::Element* el) override {
- const size_t previous_size = prefix_.size();
+ XmlPrinter(Printer* printer) : printer_(printer) {
+ }
+ void Visit(const xml::Element* el) override {
for (const xml::NamespaceDecl& decl : el->namespace_decls) {
- std::cerr << prefix_ << "N: " << decl.prefix << "=" << decl.uri
- << " (line=" << decl.line_number << ")\n";
- prefix_ += " ";
+ printer_->Println(StringPrintf("N: %s=%s (line=%zu)", decl.prefix.c_str(), decl.uri.c_str(),
+ decl.line_number));
+ printer_->Indent();
}
- std::cerr << prefix_ << "E: ";
+ printer_->Print("E: ");
if (!el->namespace_uri.empty()) {
- std::cerr << el->namespace_uri << ":";
+ printer_->Print(el->namespace_uri);
+ printer_->Print(":");
}
- std::cerr << el->name << " (line=" << el->line_number << ")\n";
+ printer_->Println(StringPrintf("%s (line=%zu)", el->name.c_str(), el->line_number));
+ printer_->Indent();
for (const xml::Attribute& attr : el->attributes) {
- std::cerr << prefix_ << " A: ";
+ printer_->Print("A: ");
if (!attr.namespace_uri.empty()) {
- std::cerr << attr.namespace_uri << ":";
+ printer_->Print(attr.namespace_uri);
+ printer_->Print(":");
}
- std::cerr << attr.name;
+ printer_->Print(attr.name);
if (attr.compiled_attribute) {
- std::cerr << "(" << attr.compiled_attribute.value().id.value_or_default(ResourceId(0x0))
- << ")";
+ printer_->Print("(");
+ printer_->Print(
+ attr.compiled_attribute.value().id.value_or_default(ResourceId(0)).to_string());
+ printer_->Print(")");
}
- std::cerr << "=";
+ printer_->Print("=");
if (attr.compiled_value != nullptr) {
- std::cerr << *attr.compiled_value;
+ attr.compiled_value->PrettyPrint(printer_);
} else {
- std::cerr << attr.value;
+ printer_->Print("\"");
+ printer_->Print(attr.value);
+ printer_->Print("\"");
}
- std::cerr << "\n";
+
+ if (!attr.value.empty()) {
+ printer_->Print(" (Raw: \"");
+ printer_->Print(attr.value);
+ printer_->Print("\")");
+ }
+ printer_->Println();
}
- prefix_ += " ";
+ printer_->Indent();
xml::ConstVisitor::Visit(el);
- prefix_.resize(previous_size);
+ printer_->Undent();
+ printer_->Undent();
+
+ for (size_t i = 0; i < el->namespace_decls.size(); i++) {
+ printer_->Undent();
+ }
}
void Visit(const xml::Text* text) override {
- std::cerr << prefix_ << "T: '" << text->text << "'\n";
+ printer_->Println(StringPrintf("T: '%s'", text->text.c_str()));
}
private:
- std::string prefix_;
+ Printer* printer_;
};
} // namespace
-void Debug::DumpXml(const xml::XmlResource& doc) {
- XmlPrinter printer;
- doc.root->Accept(&printer);
+void Debug::DumpXml(const xml::XmlResource& doc, Printer* printer) {
+ XmlPrinter xml_visitor(printer);
+ doc.root->Accept(&xml_visitor);
}
} // namespace aapt
diff --git a/tools/aapt2/Debug.h b/tools/aapt2/Debug.h
index 6209a04c3c2d..382707e1d4cd 100644
--- a/tools/aapt2/Debug.h
+++ b/tools/aapt2/Debug.h
@@ -37,7 +37,7 @@ struct Debug {
text::Printer* printer);
static void PrintStyleGraph(ResourceTable* table, const ResourceName& target_style);
static void DumpHex(const void* data, size_t len);
- static void DumpXml(const xml::XmlResource& doc);
+ static void DumpXml(const xml::XmlResource& doc, text::Printer* printer);
};
} // namespace aapt
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index 20a9f417228c..ac28227b8778 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -222,7 +222,9 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table
} else if (manifest != nullptr && path == "AndroidManifest.xml") {
BigBuffer buffer(8192);
- XmlFlattener xml_flattener(&buffer, {});
+ XmlFlattenerOptions xml_flattener_options;
+ xml_flattener_options.use_utf16 = true;
+ XmlFlattener xml_flattener(&buffer, xml_flattener_options);
if (!xml_flattener.Consume(context, manifest)) {
context->GetDiagnostics()->Error(DiagMessage(path) << "flattening failed");
return false;
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 02ac86c94b46..628466d0a281 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -520,6 +520,10 @@ std::unique_ptr<BinaryPrimitive> TryParseInt(const StringPiece& str) {
return util::make_unique<BinaryPrimitive>(value);
}
+std::unique_ptr<BinaryPrimitive> MakeInt(uint32_t val) {
+ return util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_INT_DEC, val);
+}
+
std::unique_ptr<BinaryPrimitive> TryParseFloat(const StringPiece& str) {
std::u16string str16 = util::Utf8ToUtf16(util::TrimWhitespace(str));
android::Res_value value;
diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h
index 36f6c2bda8f8..f83d49ee5591 100644
--- a/tools/aapt2/ResourceUtils.h
+++ b/tools/aapt2/ResourceUtils.h
@@ -165,6 +165,9 @@ std::unique_ptr<BinaryPrimitive> MakeBool(bool val);
*/
std::unique_ptr<BinaryPrimitive> TryParseInt(const android::StringPiece& str);
+// Returns an integer BinaryPrimitive.
+std::unique_ptr<BinaryPrimitive> MakeInt(uint32_t value);
+
/*
* Returns a BinaryPrimitve object representing a floating point number
* (float, dimension, etc) if the string was parsed as one.
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index 77cee0683f3e..6f213e19e5f6 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -369,6 +369,19 @@ FileReference* FileReference::Clone(StringPool* new_pool) const {
void FileReference::Print(std::ostream* out) const {
*out << "(file) " << *path;
+ switch (type) {
+ case ResourceFile::Type::kBinaryXml:
+ *out << " type=XML";
+ break;
+ case ResourceFile::Type::kProtoXml:
+ *out << " type=protoXML";
+ break;
+ case ResourceFile::Type::kPng:
+ *out << " type=PNG";
+ break;
+ default:
+ break;
+ }
}
BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) {
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index d80307cd154a..7f956c525bed 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -139,6 +139,7 @@ class BinaryApkSerializer : public IApkSerializer {
BigBuffer buffer(4096);
XmlFlattenerOptions options = {};
options.use_utf16 = utf16;
+ options.keep_raw_values = true;
XmlFlattener flattener(&buffer, options);
if (!flattener.Consume(context_, xml)) {
return false;
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index 3d2fb556cf59..8e7e5e59bc31 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -38,6 +38,13 @@ using ::android::base::StringPrintf;
namespace aapt {
+struct DumpOptions {
+ DebugPrintTableOptions print_options;
+
+ // The path to a file within an APK to dump.
+ Maybe<std::string> file_to_dump_path;
+};
+
static const char* ResourceFileTypeToString(const ResourceFile::Type& type) {
switch (type) {
case ResourceFile::Type::kPng:
@@ -69,8 +76,52 @@ static void DumpCompiledFile(const ResourceFile& file, const Source& source, off
printer->Println(StringPrintf("Data: offset=%" PRIi64 " length=%zd", offset, len));
}
+static bool DumpXmlFile(IAaptContext* context, io::IFile* file, bool proto,
+ text::Printer* printer) {
+ std::unique_ptr<xml::XmlResource> doc;
+ if (proto) {
+ std::unique_ptr<io::InputStream> in = file->OpenInputStream();
+ if (in == nullptr) {
+ context->GetDiagnostics()->Error(DiagMessage() << "failed to open file");
+ return false;
+ }
+
+ io::ZeroCopyInputAdaptor adaptor(in.get());
+ pb::XmlNode pb_node;
+ if (!pb_node.ParseFromZeroCopyStream(&adaptor)) {
+ context->GetDiagnostics()->Error(DiagMessage() << "failed to parse file as proto XML");
+ return false;
+ }
+
+ std::string err;
+ doc = DeserializeXmlResourceFromPb(pb_node, &err);
+ if (doc == nullptr) {
+ context->GetDiagnostics()->Error(DiagMessage() << "failed to deserialize proto XML");
+ return false;
+ }
+ printer->Println("Proto XML");
+ } else {
+ std::unique_ptr<io::IData> data = file->OpenAsData();
+ if (data == nullptr) {
+ context->GetDiagnostics()->Error(DiagMessage() << "failed to open file");
+ return false;
+ }
+
+ std::string err;
+ doc = xml::Inflate(data->data(), data->size(), &err);
+ if (doc == nullptr) {
+ context->GetDiagnostics()->Error(DiagMessage() << "failed to parse file as binary XML");
+ return false;
+ }
+ printer->Println("Binary XML");
+ }
+
+ Debug::DumpXml(*doc, printer);
+ return true;
+}
+
static bool TryDumpFile(IAaptContext* context, const std::string& file_path,
- const DebugPrintTableOptions& print_options) {
+ const DumpOptions& options) {
// Use a smaller buffer so that there is less latency for dumping to stdout.
constexpr size_t kStdOutBufferSize = 1024u;
io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
@@ -80,7 +131,10 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path,
std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(file_path, &err);
if (zip) {
ResourceTable table;
+ bool proto = false;
if (io::IFile* file = zip->FindFile("resources.pb")) {
+ proto = true;
+
std::unique_ptr<io::IData> data = file->OpenAsData();
if (data == nullptr) {
context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.pb");
@@ -98,8 +152,6 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path,
<< "failed to parse table: " << err);
return false;
}
-
- printer.Println("Proto APK");
} else if (io::IFile* file = zip->FindFile("resources.arsc")) {
std::unique_ptr<io::IData> data = file->OpenAsData();
if (!data) {
@@ -112,12 +164,26 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path,
if (!parser.Parse()) {
return false;
}
+ }
- printer.Println("Binary APK");
+ if (!options.file_to_dump_path) {
+ if (proto) {
+ printer.Println("Proto APK");
+ } else {
+ printer.Println("Binary APK");
+ }
+ Debug::PrintTable(table, options.print_options, &printer);
+ return true;
}
- Debug::PrintTable(table, print_options, &printer);
- return true;
+ io::IFile* file = zip->FindFile(options.file_to_dump_path.value());
+ if (file == nullptr) {
+ context->GetDiagnostics()->Error(DiagMessage(file_path)
+ << "file '" << options.file_to_dump_path.value()
+ << "' not found in APK");
+ return false;
+ }
+ return DumpXmlFile(context, file, proto, &printer);
}
err.clear();
@@ -159,7 +225,7 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path,
}
printer.Indent();
- Debug::PrintTable(table, print_options, &printer);
+ Debug::PrintTable(table, options.print_options, &printer);
printer.Undent();
} else if (entry->Type() == ContainerEntryType::kResFile) {
printer.Println("kResFile");
@@ -243,10 +309,13 @@ class DumpContext : public IAaptContext {
int Dump(const std::vector<StringPiece>& args) {
bool verbose = false;
bool no_values = false;
+ DumpOptions options;
Flags flags = Flags()
.OptionalSwitch("--no-values",
"Suppresses output of values when displaying resource tables.",
&no_values)
+ .OptionalFlag("--file", "Dumps the specified file from the APK passed as arg.",
+ &options.file_to_dump_path)
.OptionalSwitch("-v", "increase verbosity of output", &verbose);
if (!flags.Parse("aapt2 dump", args, &std::cerr)) {
return 1;
@@ -255,11 +324,10 @@ int Dump(const std::vector<StringPiece>& args) {
DumpContext context;
context.SetVerbose(verbose);
- DebugPrintTableOptions dump_table_options;
- dump_table_options.show_sources = true;
- dump_table_options.show_values = !no_values;
+ options.print_options.show_sources = true;
+ options.print_options.show_values = !no_values;
for (const std::string& arg : flags.GetArgs()) {
- if (!TryDumpFile(&context, arg, dump_table_options)) {
+ if (!TryDumpFile(&context, arg, options)) {
return 1;
}
}
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 15c5eaecd102..12ab88345411 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -514,6 +514,17 @@ std::vector<std::unique_ptr<xml::XmlResource>> ResourceFileFlattener::LinkAndVer
return xml_compat_versioner.Process(context_, doc, api_range);
}
+ResourceFile::Type XmlFileTypeForOutputFormat(OutputFormat format) {
+ switch (format) {
+ case OutputFormat::kApk:
+ return ResourceFile::Type::kBinaryXml;
+ case OutputFormat::kProto:
+ return ResourceFile::Type::kProtoXml;
+ }
+ LOG_ALWAYS_FATAL("unreachable");
+ return ResourceFile::Type::kUnknown;
+}
+
bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archive_writer) {
bool error = false;
std::map<std::pair<ConfigDescription, StringPiece>, FileOperation> config_sorted_files;
@@ -587,6 +598,9 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
}
}
+ // Update the type that this file will be written as.
+ file_ref->type = XmlFileTypeForOutputFormat(options_.output_format);
+
file_op.xml_to_flatten->file.config = config_value->config;
file_op.xml_to_flatten->file.source = file_ref->GetSource();
file_op.xml_to_flatten->file.name = ResourceName(pkg->name, type->type, entry->name);
@@ -625,12 +639,16 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
<< config << "' -> '" << doc->file.config << "'");
}
- dst_path =
- ResourceUtils::BuildResourceFileName(doc->file, context_->GetNameMangler());
- bool result =
- table->AddFileReferenceMangled(doc->file.name, doc->file.config, doc->file.source,
- dst_path, nullptr, context_->GetDiagnostics());
- if (!result) {
+ const ResourceFile& file = doc->file;
+ dst_path = ResourceUtils::BuildResourceFileName(file, context_->GetNameMangler());
+
+ std::unique_ptr<FileReference> file_ref =
+ util::make_unique<FileReference>(table->string_pool.MakeRef(dst_path));
+ file_ref->SetSource(doc->file.source);
+ // Update the output format of this XML file.
+ file_ref->type = XmlFileTypeForOutputFormat(options_.output_format);
+ if (!table->AddResourceMangled(file.name, file.config, {}, std::move(file_ref),
+ context_->GetDiagnostics())) {
return false;
}
}
diff --git a/tools/aapt2/configuration/ConfigurationParser.cpp b/tools/aapt2/configuration/ConfigurationParser.cpp
index eabeb47fccec..902334b98d00 100644
--- a/tools/aapt2/configuration/ConfigurationParser.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser.cpp
@@ -20,6 +20,7 @@
#include <functional>
#include <map>
#include <memory>
+#include <string>
#include <utility>
#include "android-base/file.h"
@@ -93,6 +94,7 @@ class NoopDiagnostics : public IDiagnostics {
};
NoopDiagnostics noop_;
+/** Returns the value of the label attribute for a given element. */
std::string GetLabel(const Element* element, IDiagnostics* diag) {
std::string label;
for (const auto& attr : element->attributes) {
@@ -108,6 +110,18 @@ std::string GetLabel(const Element* element, IDiagnostics* diag) {
return label;
}
+/** Returns the value of the version-code-order attribute for a given element. */
+Maybe<int32_t> GetVersionCodeOrder(const Element* element, IDiagnostics* diag) {
+ const xml::Attribute* version = element->FindAttribute("", "version-code-order");
+ if (version == nullptr) {
+ std::string label = GetLabel(element, diag);
+ diag->Error(DiagMessage() << "No version-code-order found for element '" << element->name
+ << "' with label '" << label << "'");
+ return {};
+ }
+ return std::stoi(version->value);
+}
+
/** XML node visitor that removes all of the namespace URIs from the node and all children. */
class NamespaceVisitor : public xml::Visitor {
public:
@@ -437,26 +451,37 @@ Maybe<std::vector<OutputArtifact>> ConfigurationParser::Parse(
// Convert from a parsed configuration to a list of artifacts for processing.
const std::string& apk_name = file::GetFilename(apk_path).to_string();
std::vector<OutputArtifact> output_artifacts;
- bool has_errors = false;
PostProcessingConfiguration& config = maybe_config.value();
- config.SortArtifacts();
+ bool valid = true;
int version = 1;
+
for (const ConfiguredArtifact& artifact : config.artifacts) {
Maybe<OutputArtifact> output_artifact = ToOutputArtifact(artifact, apk_name, config, diag_);
if (!output_artifact) {
// Defer return an error condition so that all errors are reported.
- has_errors = true;
+ valid = false;
} else {
output_artifact.value().version = version++;
output_artifacts.push_back(std::move(output_artifact.value()));
}
}
- if (has_errors) {
+ if (!config.ValidateVersionCodeOrdering(diag_)) {
+ diag_->Error(DiagMessage() << "could not validate post processing configuration");
+ valid = false;
+ }
+
+ if (valid) {
+ // Sorting artifacts requires that all references are valid as it uses them to determine order.
+ config.SortArtifacts();
+ }
+
+ if (!valid) {
return {};
}
+
return {output_artifacts};
}
@@ -509,8 +534,15 @@ bool AbiGroupTagHandler(PostProcessingConfiguration* config, Element* root_eleme
return false;
}
- auto& group = GetOrCreateGroup(label, &config->abi_groups);
bool valid = true;
+ OrderedEntry<Abi>& entry = config->abi_groups[label];
+ Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag);
+ if (!order) {
+ valid = false;
+ } else {
+ entry.order = order.value();
+ }
+ auto& group = entry.entry;
// Special case for empty abi-group tag. Label will be used as the ABI.
if (root_element->GetChildElements().empty()) {
@@ -519,7 +551,7 @@ bool AbiGroupTagHandler(PostProcessingConfiguration* config, Element* root_eleme
return false;
}
group.push_back(abi->second);
- return true;
+ return valid;
}
for (auto* child : root_element->GetChildElements()) {
@@ -553,8 +585,15 @@ bool ScreenDensityGroupTagHandler(PostProcessingConfiguration* config, Element*
return false;
}
- auto& group = GetOrCreateGroup(label, &config->screen_density_groups);
bool valid = true;
+ OrderedEntry<ConfigDescription>& entry = config->screen_density_groups[label];
+ Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag);
+ if (!order) {
+ valid = false;
+ } else {
+ entry.order = order.value();
+ }
+ auto& group = entry.entry;
// Special case for empty screen-density-group tag. Label will be used as the screen density.
if (root_element->GetChildElements().empty()) {
@@ -613,8 +652,15 @@ bool LocaleGroupTagHandler(PostProcessingConfiguration* config, Element* root_el
return false;
}
- auto& group = GetOrCreateGroup(label, &config->locale_groups);
bool valid = true;
+ OrderedEntry<ConfigDescription>& entry = config->locale_groups[label];
+ Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag);
+ if (!order) {
+ valid = false;
+ } else {
+ entry.order = order.value();
+ }
+ auto& group = entry.entry;
// Special case to auto insert a locale for an empty group. Label will be used for locale.
if (root_element->GetChildElements().empty()) {
@@ -728,8 +774,15 @@ bool GlTextureGroupTagHandler(PostProcessingConfiguration* config, Element* root
return false;
}
- auto& group = GetOrCreateGroup(label, &config->gl_texture_groups);
bool valid = true;
+ OrderedEntry<GlTexture>& entry = config->gl_texture_groups[label];
+ Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag);
+ if (!order) {
+ valid = false;
+ } else {
+ entry.order = order.value();
+ }
+ auto& group = entry.entry;
GlTexture result;
for (auto* child : root_element->GetChildElements()) {
@@ -771,8 +824,15 @@ bool DeviceFeatureGroupTagHandler(PostProcessingConfiguration* config, Element*
return false;
}
- auto& group = GetOrCreateGroup(label, &config->device_feature_groups);
bool valid = true;
+ OrderedEntry<DeviceFeature>& entry = config->device_feature_groups[label];
+ Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag);
+ if (!order) {
+ valid = false;
+ } else {
+ entry.order = order.value();
+ }
+ auto& group = entry.entry;
for (auto* child : root_element->GetChildElements()) {
if (child->name != "supports-feature") {
diff --git a/tools/aapt2/configuration/ConfigurationParser.internal.h b/tools/aapt2/configuration/ConfigurationParser.internal.h
index a583057427e6..f071a69fc9e3 100644
--- a/tools/aapt2/configuration/ConfigurationParser.internal.h
+++ b/tools/aapt2/configuration/ConfigurationParser.internal.h
@@ -33,18 +33,31 @@ namespace configuration {
template <typename T>
struct OrderedEntry {
- size_t order;
+ int32_t order;
std::vector<T> entry;
};
-/** A mapping of group labels to group of configuration items. */
-template <class T>
-using Group = std::unordered_map<std::string, OrderedEntry<T>>;
-
/** A mapping of group label to a single configuration item. */
template <class T>
using Entry = std::unordered_map<std::string, T>;
+/** A mapping of group labels to group of configuration items. */
+template <class T>
+using Group = Entry<OrderedEntry<T>>;
+
+template<typename T>
+bool IsGroupValid(const Group<T>& group, const std::string& name, IDiagnostics* diag) {
+ std::set<int32_t> orders;
+ for (const auto& p : group) {
+ orders.insert(p.second.order);
+ }
+ bool valid = orders.size() == group.size();
+ if (!valid) {
+ diag->Error(DiagMessage() << name << " have overlapping version-code-order attributes");
+ }
+ return valid;
+}
+
/** Retrieves an entry from the provided Group, creating a new instance if one does not exist. */
template <typename T>
std::vector<T>& GetOrCreateGroup(std::string label, Group<T>* group) {
@@ -93,7 +106,7 @@ class ComparisonChain {
private:
template <typename T>
- inline size_t GetGroupOrder(const Group<T>& groups, const Maybe<std::string>& label) {
+ inline size_t GetGroupOrder(const Entry<T>& groups, const Maybe<std::string>& label) {
if (!label) {
return std::numeric_limits<size_t>::max();
}
@@ -141,6 +154,15 @@ struct PostProcessingConfiguration {
Group<GlTexture> gl_texture_groups;
Entry<AndroidSdk> android_sdks;
+ bool ValidateVersionCodeOrdering(IDiagnostics* diag) {
+ bool valid = IsGroupValid(abi_groups, "abi-groups", diag);
+ valid &= IsGroupValid(screen_density_groups, "screen-density-groups", diag);
+ valid &= IsGroupValid(locale_groups, "locale-groups", diag);
+ valid &= IsGroupValid(device_feature_groups, "device-feature-groups", diag);
+ valid &= IsGroupValid(gl_texture_groups, "gl-texture-groups", diag);
+ return valid;
+ }
+
/**
* Sorts the configured artifacts based on the ordering of the groups in the configuration file.
* The only exception to this rule is Android SDK versions. Larger SDK versions will have a larger
diff --git a/tools/aapt2/configuration/ConfigurationParser_test.cpp b/tools/aapt2/configuration/ConfigurationParser_test.cpp
index 0329846a5bb5..febbb2ed11a0 100644
--- a/tools/aapt2/configuration/ConfigurationParser_test.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser_test.cpp
@@ -82,22 +82,22 @@ using ::testing::StrEq;
constexpr const char* kValidConfig = R"(<?xml version="1.0" encoding="utf-8" ?>
<post-process xmlns="http://schemas.android.com/tools/aapt">
<abi-groups>
- <abi-group label="arm">
- <abi>armeabi-v7a</abi>
- <abi>arm64-v8a</abi>
- </abi-group>
- <abi-group label="other">
+ <abi-group label="other" version-code-order="2">
<abi>x86</abi>
<abi>mips</abi>
</abi-group>
+ <abi-group label="arm" version-code-order="1">
+ <abi>armeabi-v7a</abi>
+ <abi>arm64-v8a</abi>
+ </abi-group>
</abi-groups>
<screen-density-groups>
- <screen-density-group label="large">
+ <screen-density-group label="large" version-code-order="2">
<screen-density>xhdpi</screen-density>
<screen-density>xxhdpi</screen-density>
<screen-density>xxxhdpi</screen-density>
</screen-density-group>
- <screen-density-group label="alldpi">
+ <screen-density-group label="alldpi" version-code-order="1">
<screen-density>ldpi</screen-density>
<screen-density>mdpi</screen-density>
<screen-density>hdpi</screen-density>
@@ -107,17 +107,20 @@ constexpr const char* kValidConfig = R"(<?xml version="1.0" encoding="utf-8" ?>
</screen-density-group>
</screen-density-groups>
<locale-groups>
- <locale-group label="europe">
+ <locale-group label="europe" version-code-order="1">
<locale>en</locale>
<locale>es</locale>
<locale>fr</locale>
<locale>de</locale>
</locale-group>
- <locale-group label="north-america">
+ <locale-group label="north-america" version-code-order="2">
<locale>en</locale>
<locale>es-rMX</locale>
<locale>fr-rCA</locale>
</locale-group>
+ <locale-group label="all" version-code-order="-1">
+ <locale />
+ </locale-group>
</locale-groups>
<android-sdks>
<android-sdk
@@ -131,14 +134,14 @@ constexpr const char* kValidConfig = R"(<?xml version="1.0" encoding="utf-8" ?>
</android-sdk>
</android-sdks>
<gl-texture-groups>
- <gl-texture-group label="dxt1">
+ <gl-texture-group label="dxt1" version-code-order="2">
<gl-texture name="GL_EXT_texture_compression_dxt1">
<texture-path>assets/dxt1/*</texture-path>
</gl-texture>
</gl-texture-group>
</gl-texture-groups>
<device-feature-groups>
- <device-feature-group label="low-latency">
+ <device-feature-group label="low-latency" version-code-order="2">
<supports-feature>android.hardware.audio.low_latency</supports-feature>
</device-feature-group>
</device-feature-groups>
@@ -188,19 +191,22 @@ TEST_F(ConfigurationParserTest, ExtractConfiguration) {
auto& arm = config.abi_groups["arm"];
auto& other = config.abi_groups["other"];
- EXPECT_EQ(arm.order, 1ul);
- EXPECT_EQ(other.order, 2ul);
+ EXPECT_EQ(arm.order, 1);
+ EXPECT_EQ(other.order, 2);
auto& large = config.screen_density_groups["large"];
auto& alldpi = config.screen_density_groups["alldpi"];
- EXPECT_EQ(large.order, 1ul);
- EXPECT_EQ(alldpi.order, 2ul);
+ EXPECT_EQ(large.order, 2);
+ EXPECT_EQ(alldpi.order, 1);
auto& north_america = config.locale_groups["north-america"];
auto& europe = config.locale_groups["europe"];
+ auto& all = config.locale_groups["all"];
// Checked in reverse to make sure access order does not matter.
- EXPECT_EQ(north_america.order, 2ul);
- EXPECT_EQ(europe.order, 1ul);
+ EXPECT_EQ(north_america.order, 2);
+ EXPECT_EQ(europe.order, 1);
+ EXPECT_EQ(all.order, -1);
+ EXPECT_EQ(3ul, config.locale_groups.size());
}
TEST_F(ConfigurationParserTest, ValidateFile) {
@@ -392,7 +398,7 @@ TEST_F(ConfigurationParserTest, ArtifactFormatAction) {
TEST_F(ConfigurationParserTest, AbiGroupAction) {
static constexpr const char* xml = R"xml(
- <abi-group label="arm">
+ <abi-group label="arm" version-code-order="2">
<!-- First comment. -->
<abi>
armeabi-v7a
@@ -415,7 +421,8 @@ TEST_F(ConfigurationParserTest, AbiGroupAction) {
}
TEST_F(ConfigurationParserTest, AbiGroupAction_EmptyGroup) {
- static constexpr const char* xml = R"xml(<abi-group label="arm64-v8a"/>)xml";
+ static constexpr const char* xml =
+ R"xml(<abi-group label="arm64-v8a" version-code-order="3"/>)xml";
auto doc = test::BuildXmlDom(xml);
@@ -426,12 +433,23 @@ TEST_F(ConfigurationParserTest, AbiGroupAction_EmptyGroup) {
EXPECT_THAT(config.abi_groups, SizeIs(1ul));
ASSERT_EQ(1u, config.abi_groups.count("arm64-v8a"));
- auto& out = config.abi_groups["arm64-v8a"].entry;
- ASSERT_THAT(out, ElementsAre(Abi::kArm64V8a));
+ auto& out = config.abi_groups["arm64-v8a"];
+ ASSERT_THAT(out.entry, ElementsAre(Abi::kArm64V8a));
+ EXPECT_EQ(3, out.order);
+}
+
+TEST_F(ConfigurationParserTest, AbiGroupAction_EmptyGroup_NoOrder) {
+ static constexpr const char* xml = R"xml(<abi-group label="arm64-v8a"/>)xml";
+
+ auto doc = test::BuildXmlDom(xml);
+
+ PostProcessingConfiguration config;
+ bool ok = AbiGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ ASSERT_FALSE(ok);
}
TEST_F(ConfigurationParserTest, AbiGroupAction_InvalidEmptyGroup) {
- static constexpr const char* xml = R"xml(<abi-group label="arm"/>)xml";
+ static constexpr const char* xml = R"xml(<abi-group label="arm" order="2"/>)xml";
auto doc = test::BuildXmlDom(xml);
@@ -442,7 +460,7 @@ TEST_F(ConfigurationParserTest, AbiGroupAction_InvalidEmptyGroup) {
TEST_F(ConfigurationParserTest, ScreenDensityGroupAction) {
static constexpr const char* xml = R"xml(
- <screen-density-group label="large">
+ <screen-density-group label="large" version-code-order="2">
<screen-density>xhdpi</screen-density>
<screen-density>
xxhdpi
@@ -471,7 +489,8 @@ TEST_F(ConfigurationParserTest, ScreenDensityGroupAction) {
}
TEST_F(ConfigurationParserTest, ScreenDensityGroupAction_EmtpyGroup) {
- static constexpr const char* xml = R"xml(<screen-density-group label="xhdpi"/>)xml";
+ static constexpr const char* xml =
+ R"xml(<screen-density-group label="xhdpi" version-code-order="4"/>)xml";
auto doc = test::BuildXmlDom(xml);
@@ -485,8 +504,19 @@ TEST_F(ConfigurationParserTest, ScreenDensityGroupAction_EmtpyGroup) {
ConfigDescription xhdpi;
xhdpi.density = ResTable_config::DENSITY_XHIGH;
- auto& out = config.screen_density_groups["xhdpi"].entry;
- ASSERT_THAT(out, ElementsAre(xhdpi));
+ auto& out = config.screen_density_groups["xhdpi"];
+ EXPECT_THAT(out.entry, ElementsAre(xhdpi));
+ EXPECT_EQ(4, out.order);
+}
+
+TEST_F(ConfigurationParserTest, ScreenDensityGroupAction_EmtpyGroup_NoVersion) {
+ static constexpr const char* xml = R"xml(<screen-density-group label="xhdpi"/>)xml";
+
+ auto doc = test::BuildXmlDom(xml);
+
+ PostProcessingConfiguration config;
+ bool ok = ScreenDensityGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ ASSERT_FALSE(ok);
}
TEST_F(ConfigurationParserTest, ScreenDensityGroupAction_InvalidEmtpyGroup) {
@@ -501,7 +531,7 @@ TEST_F(ConfigurationParserTest, ScreenDensityGroupAction_InvalidEmtpyGroup) {
TEST_F(ConfigurationParserTest, LocaleGroupAction) {
static constexpr const char* xml = R"xml(
- <locale-group label="europe">
+ <locale-group label="europe" version-code-order="2">
<locale>en</locale>
<locale>es</locale>
<locale>fr</locale>
@@ -528,7 +558,7 @@ TEST_F(ConfigurationParserTest, LocaleGroupAction) {
}
TEST_F(ConfigurationParserTest, LocaleGroupAction_EmtpyGroup) {
- static constexpr const char* xml = R"xml(<locale-group label="en"/>)xml";
+ static constexpr const char* xml = R"xml(<locale-group label="en" version-code-order="6"/>)xml";
auto doc = test::BuildXmlDom(xml);
@@ -539,11 +569,22 @@ TEST_F(ConfigurationParserTest, LocaleGroupAction_EmtpyGroup) {
ASSERT_EQ(1ul, config.locale_groups.size());
ASSERT_EQ(1u, config.locale_groups.count("en"));
- const auto& out = config.locale_groups["en"].entry;
+ const auto& out = config.locale_groups["en"];
ConfigDescription en = test::ParseConfigOrDie("en");
- ASSERT_THAT(out, ElementsAre(en));
+ EXPECT_THAT(out.entry, ElementsAre(en));
+ EXPECT_EQ(6, out.order);
+}
+
+TEST_F(ConfigurationParserTest, LocaleGroupAction_EmtpyGroup_NoOrder) {
+ static constexpr const char* xml = R"xml(<locale-group label="en"/>)xml";
+
+ auto doc = test::BuildXmlDom(xml);
+
+ PostProcessingConfiguration config;
+ bool ok = LocaleGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ ASSERT_FALSE(ok);
}
TEST_F(ConfigurationParserTest, LocaleGroupAction_InvalidEmtpyGroup) {
@@ -695,7 +736,7 @@ TEST_F(ConfigurationParserTest, AndroidSdkGroupAction_NonNumeric) {
TEST_F(ConfigurationParserTest, GlTextureGroupAction) {
static constexpr const char* xml = R"xml(
- <gl-texture-group label="dxt1">
+ <gl-texture-group label="dxt1" version-code-order="2">
<gl-texture name="GL_EXT_texture_compression_dxt1">
<texture-path>assets/dxt1/main/*</texture-path>
<texture-path>
@@ -726,7 +767,7 @@ TEST_F(ConfigurationParserTest, GlTextureGroupAction) {
TEST_F(ConfigurationParserTest, DeviceFeatureGroupAction) {
static constexpr const char* xml = R"xml(
- <device-feature-group label="low-latency">
+ <device-feature-group label="low-latency" version-code-order="2">
<supports-feature>android.hardware.audio.low_latency</supports-feature>
<supports-feature>
android.hardware.audio.pro
@@ -749,6 +790,30 @@ TEST_F(ConfigurationParserTest, DeviceFeatureGroupAction) {
ASSERT_THAT(out, ElementsAre(low_latency, pro));
}
+TEST_F(ConfigurationParserTest, Group_Valid) {
+ Group<int32_t> group;
+ group["item1"].order = 1;
+ group["item2"].order = 2;
+ group["item3"].order = 3;
+ group["item4"].order = 4;
+ group["item5"].order = 5;
+ group["item6"].order = 6;
+
+ EXPECT_TRUE(IsGroupValid(group, "test", &diag_));
+}
+
+TEST_F(ConfigurationParserTest, Group_OverlappingOrder) {
+ Group<int32_t> group;
+ group["item1"].order = 1;
+ group["item2"].order = 2;
+ group["item3"].order = 3;
+ group["item4"].order = 2;
+ group["item5"].order = 5;
+ group["item6"].order = 1;
+
+ EXPECT_FALSE(IsGroupValid(group, "test", &diag_));
+}
+
// Artifact name parser test cases.
TEST(ArtifactTest, Simple) {
diff --git a/tools/aapt2/configuration/aapt2.xsd b/tools/aapt2/configuration/aapt2.xsd
index fb2f49bae7b7..a28e28be48f4 100644
--- a/tools/aapt2/configuration/aapt2.xsd
+++ b/tools/aapt2/configuration/aapt2.xsd
@@ -81,6 +81,7 @@
<xsd:element name="gl-texture" type="gl-texture" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="label" type="xsd:string"/>
+ <xsd:attribute name="version-code-order" type="xsd:unsignedInt" use="required"/>
</xsd:complexType>
<xsd:complexType name="gl-texture">
@@ -95,6 +96,7 @@
<xsd:element name="supports-feature" type="xsd:string" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="label" type="xsd:string"/>
+ <xsd:attribute name="version-code-order" type="xsd:unsignedInt" use="required"/>
</xsd:complexType>
<xsd:complexType name="abi-group">
@@ -102,6 +104,7 @@
<xsd:element name="abi" type="abi-name" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="label" type="xsd:string"/>
+ <xsd:attribute name="version-code-order" type="xsd:unsignedInt" use="required"/>
</xsd:complexType>
<xsd:simpleType name="abi-name">
@@ -122,6 +125,7 @@
<xsd:element name="screen-density" type="screen-density" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="label" type="xsd:string"/>
+ <xsd:attribute name="version-code-order" type="xsd:unsignedInt" use="required"/>
</xsd:complexType>
<xsd:simpleType name="screen-density">
@@ -158,6 +162,7 @@
<xsd:element name="locale" type="locale" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="label" type="xsd:string"/>
+ <xsd:attribute name="version-code-order" type="xsd:unsignedInt" use="required"/>
</xsd:complexType>
<xsd:complexType name="locale">
diff --git a/tools/aapt2/configuration/example/config.xml b/tools/aapt2/configuration/example/config.xml
index d8aba09e836d..e6db2a0f461b 100644
--- a/tools/aapt2/configuration/example/config.xml
+++ b/tools/aapt2/configuration/example/config.xml
@@ -36,28 +36,28 @@
</android-sdks>
<abi-groups>
- <abi-group label="arm">
+ <abi-group label="arm" version-code-order="1">
<abi>armeabi-v7a</abi>
<abi>arm64-v8a</abi>
</abi-group>
- <abi-group label="other">
+ <abi-group label="other" version-code-order="2">
<abi>x86</abi>
<abi>mips</abi>
</abi-group>
</abi-groups>
<screen-density-groups>
- <screen-density-group label="large">
+ <screen-density-group label="alldpi" version-code-order="1">
+ <screen-density>ldpi</screen-density>
+ <screen-density>mdpi</screen-density>
+ <screen-density>hdpi</screen-density>
<screen-density>xhdpi</screen-density>
<screen-density>xxhdpi</screen-density>
<screen-density>xxxhdpi</screen-density>
</screen-density-group>
- <screen-density-group label="alldpi">
- <screen-density>ldpi</screen-density>
- <screen-density>mdpi</screen-density>
- <screen-density>hdpi</screen-density>
+ <screen-density-group label="large" version-code-order="2">
<screen-density>xhdpi</screen-density>
<screen-density>xxhdpi</screen-density>
<screen-density>xxxhdpi</screen-density>
@@ -65,26 +65,26 @@
</screen-density-groups>
<locale-groups>
- <locale-group label="europe">
+ <locale-group label="europe" version-code-order="1">
<locale lang="en"/>
<locale lang="es"/>
<locale lang="fr"/>
<locale lang="de" compressed="true"/>
</locale-group>
- <locale-group label="north-america">
+ <locale-group label="north-america" version-code-order="2">
<locale lang="en"/>
<locale lang="es" region="MX"/>
<locale lang="fr" region="CA" compressed="true"/>
</locale-group>
- <locale-group label="all">
+ <locale-group label="all" version-code-order="0">
<locale compressed="true"/>
</locale-group>
</locale-groups>
<gl-texture-groups>
- <gl-texture-group label="dxt1">
+ <gl-texture-group label="dxt1" version-code-order="1">
<gl-texture name="GL_EXT_texture_compression_dxt1">
<texture-path>assets/dxt1/*</texture-path>
</gl-texture>
@@ -92,7 +92,7 @@
</gl-texture-groups>
<device-feature-groups>
- <device-feature-group label="low-latency">
+ <device-feature-group label="low-latency" version-code-order="1">
<supports-feature>android.hardware.audio.low_latency</supports-feature>
</device-feature-group>
</device-feature-groups>
diff --git a/tools/aapt2/link/XmlCompatVersioner_test.cpp b/tools/aapt2/link/XmlCompatVersioner_test.cpp
index 1ed4536c4566..a98ab0f76de4 100644
--- a/tools/aapt2/link/XmlCompatVersioner_test.cpp
+++ b/tools/aapt2/link/XmlCompatVersioner_test.cpp
@@ -23,6 +23,7 @@ using ::aapt::test::ValueEq;
using ::testing::Eq;
using ::testing::IsNull;
using ::testing::NotNull;
+using ::testing::Pointee;
using ::testing::SizeIs;
namespace aapt {
@@ -287,13 +288,13 @@ TEST_F(XmlCompatVersionerTest, DegradeRuleOverridesExistingAttribute) {
ASSERT_THAT(attr, NotNull());
ASSERT_THAT(attr->compiled_value, NotNull());
ASSERT_TRUE(attr->compiled_attribute);
- ASSERT_THAT(*attr->compiled_value, ValueEq(padding_horizontal_value));
+ ASSERT_THAT(attr->compiled_value, Pointee(ValueEq(padding_horizontal_value)));
attr = el->FindAttribute(xml::kSchemaAndroid, "paddingRight");
ASSERT_THAT(attr, NotNull());
ASSERT_THAT(attr->compiled_value, NotNull());
ASSERT_TRUE(attr->compiled_attribute);
- ASSERT_THAT(*attr->compiled_value, ValueEq(padding_horizontal_value));
+ ASSERT_THAT(attr->compiled_value, Pointee(ValueEq(padding_horizontal_value)));
EXPECT_THAT(versioned_docs[1]->file.config.sdkVersion, Eq(SDK_LOLLIPOP_MR1));
el = versioned_docs[1]->root.get();
@@ -302,21 +303,20 @@ TEST_F(XmlCompatVersionerTest, DegradeRuleOverridesExistingAttribute) {
attr = el->FindAttribute(xml::kSchemaAndroid, "paddingHorizontal");
ASSERT_THAT(attr, NotNull());
- ASSERT_THAT(attr->compiled_value, NotNull());
ASSERT_TRUE(attr->compiled_attribute);
- ASSERT_THAT(*attr->compiled_value, ValueEq(padding_horizontal_value));
+ ASSERT_THAT(attr->compiled_value, Pointee(ValueEq(padding_horizontal_value)));
attr = el->FindAttribute(xml::kSchemaAndroid, "paddingLeft");
ASSERT_THAT(attr, NotNull());
ASSERT_THAT(attr->compiled_value, NotNull());
ASSERT_TRUE(attr->compiled_attribute);
- ASSERT_THAT(*attr->compiled_value, ValueEq(padding_horizontal_value));
+ ASSERT_THAT(attr->compiled_value, Pointee(ValueEq(padding_horizontal_value)));
attr = el->FindAttribute(xml::kSchemaAndroid, "paddingRight");
ASSERT_THAT(attr, NotNull());
ASSERT_THAT(attr->compiled_value, NotNull());
ASSERT_TRUE(attr->compiled_attribute);
- ASSERT_THAT(*attr->compiled_value, ValueEq(padding_horizontal_value));
+ ASSERT_THAT(attr->compiled_value, Pointee(ValueEq(padding_horizontal_value)));
}
} // namespace aapt
diff --git a/tools/aapt2/optimize/MultiApkGenerator.cpp b/tools/aapt2/optimize/MultiApkGenerator.cpp
index 991faadcafc4..588b3316e6fa 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator.cpp
@@ -322,22 +322,56 @@ bool MultiApkGenerator::UpdateManifest(const OutputArtifact& artifact,
std::unique_ptr<xml::Element> new_screens_el = util::make_unique<xml::Element>();
new_screens_el->name = "compatible-screens";
screens_el = new_screens_el.get();
- manifest_el->InsertChild(0, std::move(new_screens_el));
+ manifest_el->AppendChild(std::move(new_screens_el));
} else {
// clear out the old element.
screens_el->GetChildElements().clear();
}
for (const auto& density : artifact.screen_densities) {
- std::unique_ptr<xml::Element> screen_el = util::make_unique<xml::Element>();
- screen_el->name = "screen";
- const char* density_str = density.toString().string();
- screen_el->attributes.push_back(xml::Attribute{kSchemaAndroid, "screenDensity", density_str});
- screens_el->AppendChild(std::move(screen_el));
+ AddScreens(density, screens_el);
}
}
return true;
}
+/**
+ * Adds a screen element with both screenSize and screenDensity set. Since we only know the density
+ * we add it for all screen sizes.
+ *
+ * This requires the resource IDs for the attributes from the framework library. Since these IDs are
+ * a part of the public API (and in public.xml) we hard code the values.
+ *
+ * The excert from the framework is as follows:
+ * <public type="attr" name="screenSize" id="0x010102ca" />
+ * <public type="attr" name="screenDensity" id="0x010102cb" />
+ */
+void MultiApkGenerator::AddScreens(const ConfigDescription& config, xml::Element* parent) {
+ // Hard coded integer representation of the supported screen sizes:
+ // small = 200
+ // normal = 300
+ // large = 400
+ // xlarge = 500
+ constexpr const uint32_t kScreenSizes[4] = {200, 300, 400, 500,};
+ constexpr const uint32_t kScreenSizeResourceId = 0x010102ca;
+ constexpr const uint32_t kScreenDensityResourceId = 0x010102cb;
+
+ for (uint32_t screen_size : kScreenSizes) {
+ std::unique_ptr<xml::Element> screen = util::make_unique<xml::Element>();
+ screen->name = "screen";
+
+ xml::Attribute* size = screen->FindOrCreateAttribute(kSchemaAndroid, "screenSize");
+ size->compiled_attribute = xml::AaptAttribute(Attribute(), {kScreenSizeResourceId});
+ size->compiled_value = ResourceUtils::MakeInt(screen_size);
+
+ xml::Attribute* density = screen->FindOrCreateAttribute(kSchemaAndroid, "screenDensity");
+ density->compiled_attribute = xml::AaptAttribute(Attribute(), {kScreenDensityResourceId});
+ density->compiled_value = ResourceUtils::MakeInt(config.density);
+
+
+ parent->AppendChild(std::move(screen));
+ }
+}
+
} // namespace aapt
diff --git a/tools/aapt2/optimize/MultiApkGenerator.h b/tools/aapt2/optimize/MultiApkGenerator.h
index 19f64cc0e588..c8588791662a 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.h
+++ b/tools/aapt2/optimize/MultiApkGenerator.h
@@ -63,6 +63,11 @@ class MultiApkGenerator {
bool UpdateManifest(const configuration::OutputArtifact& artifact,
std::unique_ptr<xml::XmlResource>* updated_manifest, IDiagnostics* diag);
+ /**
+ * Adds the <screen> elements to the parent node for the provided density configuration.
+ */
+ void AddScreens(const ConfigDescription& config, xml::Element* parent);
+
LoadedApk* apk_;
IAaptContext* context_;
};
diff --git a/tools/aapt2/test/Common.h b/tools/aapt2/test/Common.h
index 4e318a92f3fa..aca161a5189d 100644
--- a/tools/aapt2/test/Common.h
+++ b/tools/aapt2/test/Common.h
@@ -146,97 +146,70 @@ MATCHER_P(StrEq, a,
return android::StringPiece16(arg) == a;
}
-class ValueEq {
+template <typename T>
+class ValueEqImpl : public ::testing::MatcherInterface<T> {
public:
- template <typename arg_type>
- class BaseImpl : public ::testing::MatcherInterface<arg_type> {
- BaseImpl(const BaseImpl&) = default;
-
- void DescribeTo(::std::ostream* os) const override {
- *os << "is equal to " << *expected_;
- }
-
- void DescribeNegationTo(::std::ostream* os) const override {
- *os << "is not equal to " << *expected_;
- }
-
- protected:
- BaseImpl(const Value* expected) : expected_(expected) {
- }
-
- const Value* expected_;
- };
-
- template <typename T, bool>
- class Impl {};
+ explicit ValueEqImpl(const Value* expected) : expected_(expected) {
+ }
- template <typename T>
- class Impl<T, false> : public ::testing::MatcherInterface<T> {
- public:
- explicit Impl(const Value* expected) : expected_(expected) {
- }
+ bool MatchAndExplain(T x, ::testing::MatchResultListener* listener) const override {
+ return expected_->Equals(&x);
+ }
- bool MatchAndExplain(T x, ::testing::MatchResultListener* listener) const override {
- return expected_->Equals(&x);
- }
+ void DescribeTo(::std::ostream* os) const override {
+ *os << "is equal to " << *expected_;
+ }
- void DescribeTo(::std::ostream* os) const override {
- *os << "is equal to " << *expected_;
- }
+ void DescribeNegationTo(::std::ostream* os) const override {
+ *os << "is not equal to " << *expected_;
+ }
- void DescribeNegationTo(::std::ostream* os) const override {
- *os << "is not equal to " << *expected_;
- }
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ValueEqImpl);
- private:
- DISALLOW_COPY_AND_ASSIGN(Impl);
+ const Value* expected_;
+};
- const Value* expected_;
- };
+template <typename TValue>
+class ValueEqMatcher {
+ public:
+ ValueEqMatcher(TValue expected) : expected_(std::move(expected)) {
+ }
template <typename T>
- class Impl<T, true> : public ::testing::MatcherInterface<T> {
- public:
- explicit Impl(const Value* expected) : expected_(expected) {
- }
-
- bool MatchAndExplain(T x, ::testing::MatchResultListener* listener) const override {
- return expected_->Equals(x);
- }
-
- void DescribeTo(::std::ostream* os) const override {
- *os << "is equal to " << *expected_;
- }
-
- void DescribeNegationTo(::std::ostream* os) const override {
- *os << "is not equal to " << *expected_;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Impl);
+ operator ::testing::Matcher<T>() const {
+ return ::testing::Matcher<T>(new ValueEqImpl<T>(&expected_));
+ }
- const Value* expected_;
- };
+ private:
+ TValue expected_;
+};
- ValueEq(const Value& expected) : expected_(&expected) {
- }
- ValueEq(const Value* expected) : expected_(expected) {
+template <typename TValue>
+class ValueEqPointerMatcher {
+ public:
+ ValueEqPointerMatcher(const TValue* expected) : expected_(expected) {
}
- ValueEq(const ValueEq&) = default;
template <typename T>
operator ::testing::Matcher<T>() const {
- return ::testing::Matcher<T>(new Impl<T, std::is_pointer<T>::value>(expected_));
+ return ::testing::Matcher<T>(new ValueEqImpl<T>(expected_));
}
private:
- const Value* expected_;
+ const TValue* expected_;
};
-// MATCHER_P(ValueEq, a,
-// std::string(negation ? "isn't" : "is") + " equal to " + ::testing::PrintToString(a)) {
-// return arg.Equals(&a);
-//}
+template <typename TValue,
+ typename = typename std::enable_if<!std::is_pointer<TValue>::value, void>::type>
+inline ValueEqMatcher<TValue> ValueEq(TValue value) {
+ return ValueEqMatcher<TValue>(std::move(value));
+}
+
+template <typename TValue>
+inline ValueEqPointerMatcher<TValue> ValueEq(const TValue* value) {
+ return ValueEqPointerMatcher<TValue>(value);
+}
MATCHER_P(StrValueEq, a,
std::string(negation ? "isn't" : "is") + " equal to " + ::testing::PrintToString(a)) {
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index fddb6b8c5d87..7b748ce78cbc 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -244,14 +244,13 @@ static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPoo
str16 = parser->getAttributeStringValue(i, &len);
if (str16) {
attr.value = util::Utf16ToUtf8(StringPiece16(str16, len));
- } else {
- android::Res_value res_value;
- if (parser->getAttributeValue(i, &res_value) > 0) {
- attr.compiled_value = ResourceUtils::ParseBinaryResValue(
- ResourceType::kAnim, {}, parser->getStrings(), res_value, out_pool);
- }
}
+ android::Res_value res_value;
+ if (parser->getAttributeValue(i, &res_value) > 0) {
+ attr.compiled_value = ResourceUtils::ParseBinaryResValue(
+ ResourceType::kAnim, {}, parser->getStrings(), res_value, out_pool);
+ }
el->attributes.push_back(std::move(attr));
}
diff --git a/tools/aapt2/xml/XmlDom_test.cpp b/tools/aapt2/xml/XmlDom_test.cpp
index e5012d67163d..486b53ada6bb 100644
--- a/tools/aapt2/xml/XmlDom_test.cpp
+++ b/tools/aapt2/xml/XmlDom_test.cpp
@@ -23,8 +23,10 @@
#include "test/Test.h"
using ::aapt::io::StringInputStream;
+using ::aapt::test::ValueEq;
using ::testing::Eq;
using ::testing::NotNull;
+using ::testing::Pointee;
using ::testing::SizeIs;
using ::testing::StrEq;
@@ -59,6 +61,16 @@ TEST(XmlDomTest, BinaryInflate) {
doc->root->name = "Layout";
doc->root->line_number = 2u;
+ xml::Attribute attr;
+ attr.name = "text";
+ attr.namespace_uri = kSchemaAndroid;
+ attr.compiled_attribute = AaptAttribute(
+ aapt::Attribute(android::ResTable_map::TYPE_REFERENCE | android::ResTable_map::TYPE_STRING),
+ ResourceId(0x01010001u));
+ attr.value = "@string/foo";
+ attr.compiled_value = test::BuildReference("string/foo", ResourceId(0x7f010000u));
+ doc->root->attributes.push_back(std::move(attr));
+
NamespaceDecl decl;
decl.uri = kSchemaAndroid;
decl.prefix = "android";
@@ -66,7 +78,9 @@ TEST(XmlDomTest, BinaryInflate) {
doc->root->namespace_decls.push_back(decl);
BigBuffer buffer(4096);
- XmlFlattener flattener(&buffer, {});
+ XmlFlattenerOptions options;
+ options.keep_raw_values = true;
+ XmlFlattener flattener(&buffer, options);
ASSERT_TRUE(flattener.Consume(context.get(), doc.get()));
auto block = util::Copy(buffer);
@@ -75,6 +89,21 @@ TEST(XmlDomTest, BinaryInflate) {
EXPECT_THAT(new_doc->root->name, StrEq("Layout"));
EXPECT_THAT(new_doc->root->line_number, Eq(2u));
+
+ ASSERT_THAT(new_doc->root->attributes, SizeIs(1u));
+ EXPECT_THAT(new_doc->root->attributes[0].name, StrEq("text"));
+ EXPECT_THAT(new_doc->root->attributes[0].namespace_uri, StrEq(kSchemaAndroid));
+
+ // We only check that the resource ID was preserved. There is no where to encode the types that
+ // the Attribute accepts (eg: string|reference).
+ ASSERT_TRUE(new_doc->root->attributes[0].compiled_attribute);
+ EXPECT_THAT(new_doc->root->attributes[0].compiled_attribute.value().id,
+ Eq(make_value(ResourceId(0x01010001u))));
+
+ EXPECT_THAT(new_doc->root->attributes[0].value, StrEq("@string/foo"));
+ EXPECT_THAT(new_doc->root->attributes[0].compiled_value,
+ Pointee(ValueEq(Reference(ResourceId(0x7f010000u)))));
+
ASSERT_THAT(new_doc->root->namespace_decls, SizeIs(1u));
EXPECT_THAT(new_doc->root->namespace_decls[0].uri, StrEq(kSchemaAndroid));
EXPECT_THAT(new_doc->root->namespace_decls[0].prefix, StrEq("android"));
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 399b0c63e113..26248e51b884 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -309,6 +309,8 @@ def verify_class_names(clazz):
warn(clazz, None, "S1", "Class names with acronyms should be Mtp not MTP")
if re.match("[^A-Z]", clazz.name):
error(clazz, None, "S1", "Class must start with uppercase char")
+ if clazz.name.endswith("Impl"):
+ error(clazz, None, None, "Don't expose your implementation details")
def verify_method_names(clazz):
@@ -1291,6 +1293,44 @@ def verify_tense(clazz):
warn(clazz, m, None, "Unexpected tense; probably meant 'enabled'")
+def verify_icu(clazz):
+ """Verifies that richer ICU replacements are used."""
+ better = {
+ "java.util.TimeZone": "android.icu.util.TimeZone",
+ "java.util.Calendar": "android.icu.util.Calendar",
+ "java.util.Locale": "android.icu.util.ULocale",
+ "java.util.ResourceBundle": "android.icu.util.UResourceBundle",
+ "java.util.SimpleTimeZone": "android.icu.util.SimpleTimeZone",
+ "java.util.StringTokenizer": "android.icu.util.StringTokenizer",
+ "java.util.GregorianCalendar": "android.icu.util.GregorianCalendar",
+ "java.lang.Character": "android.icu.lang.UCharacter",
+ "java.text.BreakIterator": "android.icu.text.BreakIterator",
+ "java.text.Collator": "android.icu.text.Collator",
+ "java.text.DecimalFormatSymbols": "android.icu.text.DecimalFormatSymbols",
+ "java.text.NumberFormat": "android.icu.text.NumberFormat",
+ "java.text.DateFormatSymbols": "android.icu.text.DateFormatSymbols",
+ "java.text.DateFormat": "android.icu.text.DateFormat",
+ "java.text.SimpleDateFormat": "android.icu.text.SimpleDateFormat",
+ "java.text.MessageFormat": "android.icu.text.MessageFormat",
+ "java.text.DecimalFormat": "android.icu.text.DecimalFormat",
+ }
+
+ for m in clazz.ctors + clazz.methods:
+ types = []
+ types.extend(m.typ)
+ types.extend(m.args)
+ for arg in types:
+ if arg in better:
+ warn(clazz, m, None, "Type %s should be replaced with richer ICU type %s" % (arg, better[arg]))
+
+
+def verify_clone(clazz):
+ """Verify that clone() isn't implemented; see EJ page 61."""
+ for m in clazz.methods:
+ if m.name == "clone":
+ error(clazz, m, None, "Provide an explicit copy constructor instead of implementing clone()")
+
+
def examine_clazz(clazz):
"""Find all style issues in the given class."""
@@ -1352,6 +1392,8 @@ def examine_clazz(clazz):
verify_params(clazz)
verify_services(clazz)
verify_tense(clazz)
+ verify_icu(clazz)
+ verify_clone(clazz)
def examine_stream(stream):
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index e301eb140fc9..dc2ed433d345 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -102,6 +102,7 @@ cc_library_shared {
export_generated_headers: ["statslog.h"],
shared_libs: [
"liblog",
+ "libutils",
],
}
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 3dbb50306cc6..f0628c099e2e 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -105,6 +105,7 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
fprintf(out, "#include <log/log_event_list.h>\n");
fprintf(out, "#include <log/log.h>\n");
fprintf(out, "#include <statslog.h>\n");
+ fprintf(out, "#include <utils/SystemClock.h>\n");
fprintf(out, "\n");
fprintf(out, "namespace android {\n");
@@ -145,6 +146,7 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
fprintf(out, "{\n");
argIndex = 1;
fprintf(out, " android_log_event_list event(kStatsEventTag);\n");
+ fprintf(out, " event << android::elapsedRealtimeNano();\n\n");
fprintf(out, " event << code;\n\n");
for (vector<java_type_t>::const_iterator arg = signature->begin();
arg != signature->end(); arg++) {
@@ -212,6 +214,7 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
fprintf(out, "{\n");
argIndex = 1;
fprintf(out, " android_log_event_list event(kStatsEventTag);\n");
+ fprintf(out, " event << android::elapsedRealtimeNano();\n\n");
fprintf(out, " event << code;\n\n");
for (vector<java_type_t>::const_iterator arg = signature->begin();
arg != signature->end(); arg++) {
diff --git a/wifi/OWNERS b/wifi/OWNERS
new file mode 100644
index 000000000000..0efa4646a80a
--- /dev/null
+++ b/wifi/OWNERS
@@ -0,0 +1,5 @@
+set noparent
+
+etancohen@google.com
+satk@google.com
+silberst@google.com
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 897b1eaa2a64..d2cdf8d380d5 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -99,35 +99,45 @@ public class WifiManager {
// Supplicant error codes:
/**
* The error code if there was a problem authenticating.
+ * @deprecated This is no longer supported.
*/
+ @Deprecated
public static final int ERROR_AUTHENTICATING = 1;
/**
* The reason code if there is no error during authentication.
* It could also imply that there no authentication in progress,
* this reason code also serves as a reset value.
+ * @deprecated This is no longer supported.
* @hide
*/
+ @Deprecated
public static final int ERROR_AUTH_FAILURE_NONE = 0;
/**
* The reason code if there was a timeout authenticating.
+ * @deprecated This is no longer supported.
* @hide
*/
+ @Deprecated
public static final int ERROR_AUTH_FAILURE_TIMEOUT = 1;
/**
* The reason code if there was a wrong password while
* authenticating.
+ * @deprecated This is no longer supported.
* @hide
*/
+ @Deprecated
public static final int ERROR_AUTH_FAILURE_WRONG_PSWD = 2;
/**
* The reason code if there was EAP failure while
* authenticating.
+ * @deprecated This is no longer supported.
* @hide
*/
+ @Deprecated
public static final int ERROR_AUTH_FAILURE_EAP_FAILURE = 3;
/**
@@ -565,8 +575,10 @@ public class WifiManager {
* to perform Wi-Fi operations) or the connection to the supplicant has been
* lost. One extra provides the connection state as a boolean, where {@code true}
* means CONNECTED.
+ * @deprecated This is no longer supported.
* @see #EXTRA_SUPPLICANT_CONNECTED
*/
+ @Deprecated
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION =
"android.net.wifi.supplicant.CONNECTION_CHANGE";
@@ -575,7 +587,9 @@ public class WifiManager {
* the supplicant daemon has been gained or lost. {@code true} means
* a connection now exists.
* Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
+ * @deprecated This is no longer supported.
*/
+ @Deprecated
public static final String EXTRA_SUPPLICANT_CONNECTED = "connected";
/**
* Broadcast intent action indicating that the state of Wi-Fi connectivity
@@ -612,7 +626,9 @@ public class WifiManager {
* the overall state of connectivity.
* @see #EXTRA_NEW_STATE
* @see #EXTRA_SUPPLICANT_ERROR
+ * @deprecated This is no longer supported.
*/
+ @Deprecated
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String SUPPLICANT_STATE_CHANGED_ACTION =
"android.net.wifi.supplicant.STATE_CHANGE";
@@ -620,7 +636,9 @@ public class WifiManager {
* The lookup key for a {@link SupplicantState} describing the new state
* Retrieve with
* {@link android.content.Intent#getParcelableExtra(String)}.
+ * @deprecated This is no longer supported.
*/
+ @Deprecated
public static final String EXTRA_NEW_STATE = "newState";
/**
@@ -629,7 +647,9 @@ public class WifiManager {
* Retrieve with
* {@link android.content.Intent#getIntExtra(String, int)}.
* @see #ERROR_AUTHENTICATING
+ * @deprecated This is no longer supported.
*/
+ @Deprecated
public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError";
/**
@@ -638,8 +658,10 @@ public class WifiManager {
* Retrieve with
* {@link android.content.Intent#getIntExtra(String, int)}.
* @see #ERROR_AUTH_FAILURE_#REASON_CODE
+ * @deprecated This is no longer supported.
* @hide
*/
+ @Deprecated
public static final String EXTRA_SUPPLICANT_ERROR_REASON = "supplicantErrorReason";
/**
@@ -3617,8 +3639,10 @@ public class WifiManager {
* Restore state from the older version of back up data.
* The old backup data was essentially a backup of wpa_supplicant.conf
* and ipconfig.txt file.
+ * @deprecated this is no longer supported.
* @hide
*/
+ @Deprecated
public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
try {
mService.restoreSupplicantBackupData(supplicantData, ipConfigData);
diff --git a/wifi/java/android/net/wifi/WpsInfo.java b/wifi/java/android/net/wifi/WpsInfo.java
index ae2e77171367..d12cce174192 100644
--- a/wifi/java/android/net/wifi/WpsInfo.java
+++ b/wifi/java/android/net/wifi/WpsInfo.java
@@ -21,37 +21,58 @@ import android.os.Parcel;
/**
* A class representing Wi-Fi Protected Setup
- *
+ * @deprecated This class is no longer supported.
* {@see WifiP2pConfig}
*/
+@Deprecated
public class WpsInfo implements Parcelable {
- /** Push button configuration */
+ /** Push button configuration
+ * @deprecated This is no longer supported.*/
+ @Deprecated
public static final int PBC = 0;
- /** Display pin method configuration - pin is generated and displayed on device */
+ /** Display pin method configuration - pin is generated and displayed on device
+ * @deprecated This is no longer supported.*/
+ @Deprecated
public static final int DISPLAY = 1;
- /** Keypad pin method configuration - pin is entered on device */
+ /** Keypad pin method configuration - pin is entered on device
+ * @deprecated This is no longer supported.*/
+ @Deprecated
public static final int KEYPAD = 2;
- /** Label pin method configuration - pin is labelled on device */
+ /** Label pin method configuration - pin is labelled on device
+ * @deprecated This is no longer supported.*/
+ @Deprecated
public static final int LABEL = 3;
- /** Invalid configuration */
+ /** Invalid configuration
+ * @deprecated This is no longer supported.*/
+ @Deprecated
public static final int INVALID = 4;
- /** Wi-Fi Protected Setup. www.wi-fi.org/wifi-protected-setup has details */
+ /** Wi-Fi Protected Setup. www.wi-fi.org/wifi-protected-setup has details
+ * @deprecated This is no longer supported.*/
+ @Deprecated
public int setup;
- /** Passed with pin method KEYPAD */
+ /** Passed with pin method KEYPAD
+ * @deprecated This is no longer supported.*/
+ @Deprecated
public String BSSID;
- /** Passed with pin method configuration */
+ /** Passed with pin method configuration
+ * @deprecated This is no longer supported.*/
+ @Deprecated
public String pin;
+ /** @deprecated This API is no longer supported.*/
+ @Deprecated
public WpsInfo() {
setup = INVALID;
BSSID = null;
pin = null;
}
+ /** @deprecated This API is no longer supported.*/
+ @Deprecated
public String toString() {
StringBuffer sbuf = new StringBuffer();
sbuf.append(" setup: ").append(setup);
@@ -63,12 +84,16 @@ public class WpsInfo implements Parcelable {
return sbuf.toString();
}
- /** Implement the Parcelable interface */
+ /** Implement the Parcelable interface
+ * @deprecated This API is no longer supported.*/
+ @Deprecated
public int describeContents() {
return 0;
}
- /* Copy constructor */
+ /* Copy constructor
+ * @deprecated This API is no longer supported.*/
+ @Deprecated
public WpsInfo(WpsInfo source) {
if (source != null) {
setup = source.setup;
@@ -77,16 +102,22 @@ public class WpsInfo implements Parcelable {
}
}
- /** Implement the Parcelable interface */
+ /** Implement the Parcelable interface
+ * @deprecated This API is no longer supported. */
+ @Deprecated
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(setup);
dest.writeString(BSSID);
dest.writeString(pin);
}
- /** Implement the Parcelable interface */
+ /** Implement the Parcelable interface
+ * @deprecated This API is no longer supported.*/
+ @Deprecated
public static final Creator<WpsInfo> CREATOR =
new Creator<WpsInfo>() {
+ /** @deprecated This API is nolonger supported.*/
+ @Deprecated
public WpsInfo createFromParcel(Parcel in) {
WpsInfo config = new WpsInfo();
config.setup = in.readInt();
@@ -95,6 +126,8 @@ public class WpsInfo implements Parcelable {
return config;
}
+ /** @deprecated This API is nolonger supported.*/
+ @Deprecated
public WpsInfo[] newArray(int size) {
return new WpsInfo[size];
}
diff --git a/wifi/java/android/net/wifi/rtt/RangingRequest.java b/wifi/java/android/net/wifi/rtt/RangingRequest.java
index 52b3d8691c79..4348ed4f73e1 100644
--- a/wifi/java/android/net/wifi/rtt/RangingRequest.java
+++ b/wifi/java/android/net/wifi/rtt/RangingRequest.java
@@ -122,6 +122,11 @@ public final class RangingRequest implements Parcelable {
* Add the device specified by the {@link ScanResult} to the list of devices with
* which to measure range. The total number of peers added to a request cannot exceed the
* limit specified by {@link #getMaxPeers()}.
+ * <p>
+ * Ranging may not be supported if the Access Point does not support IEEE 802.11mc. Use
+ * {@link ScanResult#is80211mcResponder()} to verify the Access Point's capabilities. If
+ * not supported the result status will be
+ * {@link RangingResult#STATUS_RESPONDER_DOES_NOT_SUPPORT_IEEE80211MC}.
*
* @param apInfo Information of an Access Point (AP) obtained in a Scan Result.
* @return The builder to facilitate chaining
@@ -138,6 +143,11 @@ public final class RangingRequest implements Parcelable {
* Add the devices specified by the {@link ScanResult}s to the list of devices with
* which to measure range. The total number of peers added to a request cannot exceed the
* limit specified by {@link #getMaxPeers()}.
+ * <p>
+ * Ranging may not be supported if the Access Point does not support IEEE 802.11mc. Use
+ * {@link ScanResult#is80211mcResponder()} to verify the Access Point's capabilities. If
+ * not supported the result status will be
+ * {@link RangingResult#STATUS_RESPONDER_DOES_NOT_SUPPORT_IEEE80211MC}.
*
* @param apInfos Information of an Access Points (APs) obtained in a Scan Result.
* @return The builder to facilitate chaining
diff --git a/wifi/java/android/net/wifi/rtt/RangingResult.java b/wifi/java/android/net/wifi/rtt/RangingResult.java
index ea8b4c701be5..b155938ee356 100644
--- a/wifi/java/android/net/wifi/rtt/RangingResult.java
+++ b/wifi/java/android/net/wifi/rtt/RangingResult.java
@@ -45,7 +45,7 @@ public final class RangingResult implements Parcelable {
private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
/** @hide */
- @IntDef({STATUS_SUCCESS, STATUS_FAIL})
+ @IntDef({STATUS_SUCCESS, STATUS_FAIL, STATUS_RESPONDER_DOES_NOT_SUPPORT_IEEE80211MC})
@Retention(RetentionPolicy.SOURCE)
public @interface RangeResultStatus {
}
@@ -70,8 +70,6 @@ public final class RangingResult implements Parcelable {
* <p>
* On such a failure, the individual result fields of {@link RangingResult} such as
* {@link RangingResult#getDistanceMm()} are invalid.
- *
- * @hide
*/
public static final int STATUS_RESPONDER_DOES_NOT_SUPPORT_IEEE80211MC = 2;