summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk24
-rw-r--r--api/current.txt1
-rw-r--r--cmds/incidentd/src/Section.cpp15
-rw-r--r--cmds/incidentd/src/Section.h12
-rw-r--r--cmds/incidentd/tests/Section_test.cpp10
-rw-r--r--cmds/statsd/Android.mk1
-rw-r--r--cmds/statsd/src/FieldValue.cpp12
-rw-r--r--cmds/statsd/src/FieldValue.h1
-rw-r--r--cmds/statsd/src/StatsLogProcessor.cpp22
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h3
-rw-r--r--cmds/statsd/src/StatsService.cpp8
-rw-r--r--cmds/statsd/src/guardrail/StatsdStats.h2
-rw-r--r--cmds/statsd/src/hash.cpp130
-rw-r--r--cmds/statsd/src/hash.h46
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.cpp88
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.h3
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.cpp83
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.h3
-rw-r--r--cmds/statsd/src/metrics/EventMetricProducer.cpp5
-rw-r--r--cmds/statsd/src/metrics/EventMetricProducer.h2
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.cpp94
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.h2
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.h16
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.cpp12
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h1
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.cpp92
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.h2
-rw-r--r--cmds/statsd/src/packages/UidMap.cpp25
-rw-r--r--cmds/statsd/src/packages/UidMap.h2
-rw-r--r--cmds/statsd/src/stats_log.proto70
-rw-r--r--cmds/statsd/src/stats_log_util.cpp159
-rw-r--r--cmds/statsd/src/stats_log_util.h14
-rw-r--r--cmds/statsd/tests/FieldValue_test.cpp120
-rw-r--r--cmds/statsd/tests/StatsLogProcessor_test.cpp4
-rw-r--r--cmds/statsd/tests/UidMap_test.cpp24
-rw-r--r--cmds/statsd/tests/e2e/Attribution_e2e_test.cpp14
-rw-r--r--cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp19
-rw-r--r--cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp28
-rw-r--r--cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp17
-rw-r--r--cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp21
-rw-r--r--cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp7
-rw-r--r--cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp14
-rw-r--r--cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp22
-rw-r--r--cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp14
-rw-r--r--cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp43
-rw-r--r--cmds/statsd/tests/statsd_test_util.cpp177
-rw-r--r--cmds/statsd/tests/statsd_test_util.h96
-rw-r--r--config/hiddenapi-light-greylist.txt76
-rw-r--r--config/hiddenapi-vendor-list.txt13
-rw-r--r--core/java/android/app/ActivityManagerInternal.java11
-rw-r--r--core/java/android/app/ActivityThread.java1
-rw-r--r--core/java/android/app/AppOpsManager.java272
-rw-r--r--core/java/android/app/ContextImpl.java16
-rw-r--r--core/java/android/app/Notification.java39
-rw-r--r--core/java/android/app/NotificationChannel.java25
-rw-r--r--core/java/android/app/slice/SliceMetrics.java23
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java6
-rw-r--r--core/java/android/content/Context.java27
-rw-r--r--core/java/android/content/ContextWrapper.java7
-rw-r--r--core/java/android/content/Intent.java35
-rw-r--r--core/java/android/content/pm/ILauncherApps.aidl5
-rw-r--r--core/java/android/content/pm/LauncherApps.java6
-rw-r--r--core/java/android/content/res/Configuration.java4
-rw-r--r--core/java/android/content/res/Resources.java15
-rw-r--r--core/java/android/hardware/Camera.java101
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java33
-rw-r--r--core/java/android/hardware/radio/RadioMetadata.java23
-rw-r--r--core/java/android/os/Looper.java85
-rw-r--r--core/java/android/os/storage/VolumeInfo.java2
-rw-r--r--core/java/android/provider/Settings.java29
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java71
-rw-r--r--core/java/android/transition/ChangeBounds.java64
-rw-r--r--core/java/android/util/apk/ApkVerityBuilder.java28
-rw-r--r--core/java/android/view/SurfaceView.java12
-rw-r--r--core/java/android/view/View.java4
-rw-r--r--core/java/android/view/ViewRootImpl.java2
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java2
-rw-r--r--core/java/android/widget/Magnifier.java184
-rw-r--r--core/java/android/widget/ProgressBar.java14
-rw-r--r--core/java/com/android/internal/content/FileSystemProvider.java28
-rw-r--r--core/java/com/android/internal/content/PackageHelper.java58
-rw-r--r--core/java/com/android/internal/net/NetworkStatsFactory.java50
-rw-r--r--core/java/com/android/internal/os/BackgroundThread.java8
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java3
-rw-r--r--core/java/com/android/internal/policy/DecorContext.java16
-rw-r--r--core/java/com/android/internal/policy/DecorView.java9
-rw-r--r--core/java/com/android/internal/policy/DividerSnapAlgorithm.java2
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java2
-rw-r--r--core/java/com/android/internal/widget/MessagingGroup.java3
-rw-r--r--core/java/com/android/internal/widget/MessagingLayout.java3
-rw-r--r--core/java/com/android/internal/widget/MessagingTextMessage.java2
-rw-r--r--core/java/com/android/internal/widget/NotificationActionListLayout.java28
-rw-r--r--core/jni/com_android_internal_net_NetworkStatsFactory.cpp81
-rw-r--r--core/proto/android/app/notification_channel.proto1
-rw-r--r--core/proto/android/os/incident.proto4
-rw-r--r--core/res/AndroidManifest.xml137
-rw-r--r--core/res/res/anim-ldrtl/cross_profile_apps_thumbnail_enter.xml76
-rw-r--r--core/res/res/anim/cross_profile_apps_thumbnail_enter.xml2
-rw-r--r--core/res/res/drawable/ic_dnd_block_notifications.xml30
-rw-r--r--core/res/res/layout/magnifier.xml35
-rw-r--r--core/res/res/layout/notification_material_reply_text.xml2
-rw-r--r--core/res/res/layout/notification_template_messaging_group.xml3
-rw-r--r--core/res/res/values-mcc405/config.xml2
-rw-r--r--core/res/res/values/config.xml14
-rw-r--r--core/res/res/values/dimens.xml4
-rw-r--r--core/res/res/values/strings.xml8
-rw-r--r--core/res/res/values/symbols.xml4
-rw-r--r--core/res/res/xml/default_zen_mode_config.xml2
-rw-r--r--core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java23
-rw-r--r--core/tests/overlaytests/host/test-apps/UpdateOverlay/src/com/android/server/om/hosttest/update_overlay_test/UpdateOverlayTest.java2
-rw-r--r--libs/hwui/DeferredLayerUpdater.cpp16
-rw-r--r--libs/hwui/DeferredLayerUpdater.h7
-rw-r--r--libs/hwui/GlLayer.cpp2
-rw-r--r--libs/hwui/GlLayer.h2
-rw-r--r--libs/hwui/Layer.cpp40
-rw-r--r--libs/hwui/Layer.h28
-rw-r--r--libs/hwui/VkLayer.h2
-rw-r--r--libs/hwui/pipeline/skia/LayerDrawable.cpp11
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp2
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp2
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp3
-rw-r--r--libs/hwui/renderthread/OpenGLPipeline.cpp3
-rw-r--r--libs/hwui/tests/common/TestListViewSceneBase.cpp3
-rw-r--r--libs/hwui/tests/common/TestUtils.cpp2
-rw-r--r--libs/hwui/tests/common/TestUtils.h3
-rw-r--r--libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp3
-rw-r--r--libs/hwui/tests/common/scenes/TvApp.cpp9
-rw-r--r--libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp2
-rw-r--r--libs/hwui/utils/Color.cpp54
-rw-r--r--libs/hwui/utils/Color.h3
-rw-r--r--libs/incident/proto/android/section.proto1
-rw-r--r--packages/CaptivePortalLogin/AndroidManifest.xml1
-rw-r--r--packages/CarrierDefaultApp/AndroidManifest.xml1
-rw-r--r--packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java23
-rw-r--r--packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java29
-rw-r--r--packages/Osu/Android.mk24
-rw-r--r--packages/Osu/AndroidManifest.xml55
-rw-r--r--packages/Osu/res/layout/activity_main.xml19
-rw-r--r--packages/Osu/res/layout/list_item.xml35
-rw-r--r--packages/Osu/res/layout/osu_web_view.xml13
-rw-r--r--packages/Osu/res/mipmap-hdpi/ic_launcher.pngbin3418 -> 0 bytes
-rw-r--r--packages/Osu/res/mipmap-mdpi/ic_launcher.pngbin2206 -> 0 bytes
-rw-r--r--packages/Osu/res/mipmap-xhdpi/ic_launcher.pngbin4842 -> 0 bytes
-rw-r--r--packages/Osu/res/mipmap-xxhdpi/ic_launcher.pngbin7718 -> 0 bytes
-rw-r--r--packages/Osu/res/mipmap-xxxhdpi/ic_launcher.pngbin10486 -> 0 bytes
-rw-r--r--packages/Osu/res/values-w820dp/dimens.xml6
-rw-r--r--packages/Osu/res/values/colors.xml6
-rw-r--r--packages/Osu/res/values/dimens.xml5
-rw-r--r--packages/Osu/res/values/strings.xml4
-rw-r--r--packages/Osu/src/com/android/anqp/ANQPElement.java16
-rw-r--r--packages/Osu/src/com/android/anqp/Constants.java233
-rw-r--r--packages/Osu/src/com/android/anqp/HSIconFileElement.java91
-rw-r--r--packages/Osu/src/com/android/anqp/HSOsuProvidersElement.java49
-rw-r--r--packages/Osu/src/com/android/anqp/I18Name.java93
-rw-r--r--packages/Osu/src/com/android/anqp/IconInfo.java109
-rw-r--r--packages/Osu/src/com/android/anqp/OSUProvider.java213
-rw-r--r--packages/Osu/src/com/android/anqp/eap/AuthParam.java9
-rw-r--r--packages/Osu/src/com/android/anqp/eap/Credential.java72
-rw-r--r--packages/Osu/src/com/android/anqp/eap/EAP.java155
-rw-r--r--packages/Osu/src/com/android/anqp/eap/EAPMethod.java191
-rw-r--r--packages/Osu/src/com/android/anqp/eap/ExpandedEAPMethod.java78
-rw-r--r--packages/Osu/src/com/android/anqp/eap/InnerAuthEAP.java56
-rw-r--r--packages/Osu/src/com/android/anqp/eap/NonEAPInnerAuth.java93
-rw-r--r--packages/Osu/src/com/android/anqp/eap/VendorSpecificAuth.java47
-rw-r--r--packages/Osu/src/com/android/configparse/ConfigBuilder.java258
-rw-r--r--packages/Osu/src/com/android/hotspot2/AppBridge.java59
-rw-r--r--packages/Osu/src/com/android/hotspot2/AuthMatch.java39
-rw-r--r--packages/Osu/src/com/android/hotspot2/IMSIParameter.java96
-rw-r--r--packages/Osu/src/com/android/hotspot2/OMADMAdapter.java601
-rw-r--r--packages/Osu/src/com/android/hotspot2/PasspointMatch.java9
-rw-r--r--packages/Osu/src/com/android/hotspot2/Utils.java407
-rw-r--r--packages/Osu/src/com/android/hotspot2/app/IOSUAccessor.aidl8
-rw-r--r--packages/Osu/src/com/android/hotspot2/app/LocalServiceBinder.java15
-rw-r--r--packages/Osu/src/com/android/hotspot2/app/MainActivity.java303
-rw-r--r--packages/Osu/src/com/android/hotspot2/app/OSUData.aidl4
-rw-r--r--packages/Osu/src/com/android/hotspot2/app/OSUData.java69
-rw-r--r--packages/Osu/src/com/android/hotspot2/app/OSUService.java206
-rw-r--r--packages/Osu/src/com/android/hotspot2/asn1/Asn1Boolean.java31
-rw-r--r--packages/Osu/src/com/android/hotspot2/asn1/Asn1Class.java5
-rw-r--r--packages/Osu/src/com/android/hotspot2/asn1/Asn1Constructed.java53
-rw-r--r--packages/Osu/src/com/android/hotspot2/asn1/Asn1Decoder.java211
-rw-r--r--packages/Osu/src/com/android/hotspot2/asn1/Asn1ID.java19
-rw-r--r--packages/Osu/src/com/android/hotspot2/asn1/Asn1Integer.java56
-rw-r--r--packages/Osu/src/com/android/hotspot2/asn1/Asn1Object.java88
-rw-r--r--packages/Osu/src/com/android/hotspot2/asn1/Asn1Octets.java47
-rw-r--r--packages/Osu/src/com/android/hotspot2/asn1/Asn1Oid.java212
-rw-r--r--packages/Osu/src/com/android/hotspot2/asn1/Asn1String.java34
-rw-r--r--packages/Osu/src/com/android/hotspot2/asn1/Asn1Tag.java31
-rw-r--r--packages/Osu/src/com/android/hotspot2/asn1/DecodeException.java17
-rw-r--r--packages/Osu/src/com/android/hotspot2/asn1/OidMappings.java197
-rw-r--r--packages/Osu/src/com/android/hotspot2/est/ESTHandler.java501
-rw-r--r--packages/Osu/src/com/android/hotspot2/flow/FlowService.java168
-rw-r--r--packages/Osu/src/com/android/hotspot2/flow/IFlowService.aidl10
-rw-r--r--packages/Osu/src/com/android/hotspot2/flow/OSUInfo.aidl3
-rw-r--r--packages/Osu/src/com/android/hotspot2/flow/OSUInfo.java321
-rw-r--r--packages/Osu/src/com/android/hotspot2/flow/PlatformAdapter.java620
-rw-r--r--packages/Osu/src/com/android/hotspot2/omadm/MOManager.java1037
-rw-r--r--packages/Osu/src/com/android/hotspot2/omadm/MOTree.java269
-rw-r--r--packages/Osu/src/com/android/hotspot2/omadm/MgmtTreeRoot.java37
-rw-r--r--packages/Osu/src/com/android/hotspot2/omadm/MultiValueMap.java117
-rw-r--r--packages/Osu/src/com/android/hotspot2/omadm/NodeAttribute.java30
-rw-r--r--packages/Osu/src/com/android/hotspot2/omadm/OMAConstants.java158
-rw-r--r--packages/Osu/src/com/android/hotspot2/omadm/OMAConstructed.java169
-rw-r--r--packages/Osu/src/com/android/hotspot2/omadm/OMAException.java9
-rw-r--r--packages/Osu/src/com/android/hotspot2/omadm/OMANode.java163
-rw-r--r--packages/Osu/src/com/android/hotspot2/omadm/OMAParser.java69
-rw-r--r--packages/Osu/src/com/android/hotspot2/omadm/OMAScalar.java87
-rw-r--r--packages/Osu/src/com/android/hotspot2/omadm/XMLNode.java240
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/ClientKeyManager.java122
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/ExchangeCompleteResponse.java28
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/ExecCommand.java3
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/HTTPHandler.java180
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/IconCache.java337
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/OSUCache.java178
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/OSUCertType.java10
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/OSUClient.java540
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/OSUCommand.java130
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/OSUCommandID.java5
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/OSUError.java22
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/OSUFlowManager.java392
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/OSUListener.java5
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/OSUManager.java264
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/OSUMessageType.java5
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/OSUOperationStatus.java8
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/OSUResponse.java97
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/OSUSocketFactory.java451
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/OSUStatus.java5
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/OSUWebView.java91
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/PostDevDataResponse.java49
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/RequestReason.java16
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/ResponseFactory.java8
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/SOAPBuilder.java188
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/SOAPParser.java327
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/SPVerifier.java330
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/UserInputListener.java46
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/WiFiKeyManager.java172
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/XMLParser.java71
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/commands/BrowserURI.java32
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/commands/ClientCertInfo.java94
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/commands/GetCertData.java75
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/commands/MOData.java41
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/commands/MOURN.java33
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/commands/OSUCommandData.java7
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/service/RedirectListener.java206
-rw-r--r--packages/Osu/src/com/android/hotspot2/osu/service/RemediationHandler.java585
-rw-r--r--packages/Osu/src/com/android/hotspot2/pps/Credential.java252
-rw-r--r--packages/Osu/src/com/android/hotspot2/pps/DomainMatcher.java149
-rw-r--r--packages/Osu/src/com/android/hotspot2/pps/HomeSP.java211
-rw-r--r--packages/Osu/src/com/android/hotspot2/pps/Policy.java195
-rw-r--r--packages/Osu/src/com/android/hotspot2/pps/SubscriptionParameters.java81
-rw-r--r--packages/Osu/src/com/android/hotspot2/pps/UpdateInfo.java105
-rw-r--r--packages/Osu/src/com/android/hotspot2/utils/HTTPMessage.java36
-rw-r--r--packages/Osu/src/com/android/hotspot2/utils/HTTPRequest.java307
-rw-r--r--packages/Osu/src/com/android/hotspot2/utils/HTTPResponse.java181
-rw-r--r--packages/Osu2/Android.mk20
-rw-r--r--packages/Osu2/AndroidManifest.xml34
-rw-r--r--packages/Osu2/res/layout/activity_main.xml6
-rw-r--r--packages/Osu2/res/mipmap-hdpi/ic_launcher.pngbin3418 -> 0 bytes
-rw-r--r--packages/Osu2/res/mipmap-mdpi/ic_launcher.pngbin2206 -> 0 bytes
-rw-r--r--packages/Osu2/res/mipmap-xhdpi/ic_launcher.pngbin4842 -> 0 bytes
-rw-r--r--packages/Osu2/res/mipmap-xxhdpi/ic_launcher.pngbin7718 -> 0 bytes
-rw-r--r--packages/Osu2/res/mipmap-xxxhdpi/ic_launcher.pngbin10486 -> 0 bytes
-rw-r--r--packages/Osu2/res/values-w820dp/dimens.xml6
-rw-r--r--packages/Osu2/res/values/colors.xml6
-rw-r--r--packages/Osu2/res/values/dimens.xml5
-rw-r--r--packages/Osu2/res/values/strings.xml3
-rw-r--r--packages/Osu2/src/com/android/osu/Constants.java24
-rw-r--r--packages/Osu2/src/com/android/osu/MainActivity.java76
-rw-r--r--packages/Osu2/src/com/android/osu/NetworkConnection.java206
-rw-r--r--packages/Osu2/src/com/android/osu/OsuService.java33
-rw-r--r--packages/Osu2/src/com/android/osu/ProvisionService.java119
-rw-r--r--packages/Osu2/tests/Android.mk44
-rw-r--r--packages/Osu2/tests/AndroidManifest.xml38
-rw-r--r--packages/Osu2/tests/AndroidTest.xml30
-rw-r--r--packages/Osu2/tests/README.md45
-rwxr-xr-xpackages/Osu2/tests/runtests.sh24
-rw-r--r--packages/Osu2/tests/src/com/android/osu/NetworkConnectionTest.java132
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java29
-rw-r--r--packages/SystemUI/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml53
-rw-r--r--packages/SystemUI/res/drawable/ic_memory.xml28
-rw-r--r--packages/SystemUI/res/drawable/smart_reply_button_background.xml4
-rw-r--r--packages/SystemUI/res/layout/app_ops_info.xml6
-rw-r--r--packages/SystemUI/res/layout/menu_ime.xml1
-rw-r--r--packages/SystemUI/res/layout/notification_info.xml40
-rw-r--r--packages/SystemUI/res/layout/qs_paged_page.xml4
-rw-r--r--packages/SystemUI/res/layout/smart_reply_button.xml2
-rw-r--r--packages/SystemUI/res/layout/status_bar_dnd_suppressing_notifications.xml34
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_footer.xml3
-rw-r--r--packages/SystemUI/res/layout/status_bar_wifi_group.xml2
-rw-r--r--packages/SystemUI/res/values/colors.xml2
-rw-r--r--packages/SystemUI/res/values/config.xml2
-rw-r--r--packages/SystemUI/res/values/dimens.xml24
-rw-r--r--packages/SystemUI/res/values/strings.xml9
-rw-r--r--packages/SystemUI/res/values/styles.xml6
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/MetricsLoggerCompat.java10
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java25
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java8
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java17
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/Prefs.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/TileLayout.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java74
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java73
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java50
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/DndSuppressingNotificationsView.java91
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCounters.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java73
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java72
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java74
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/leak/DumpTruck.java175
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java443
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java57
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java38
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardPresentationTest.java41
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java86
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java42
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/leak/GarbageMonitorTest.java72
-rw-r--r--proto/src/metrics_constants.proto23
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java12
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java16
-rw-r--r--services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java14
-rw-r--r--services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java2
-rw-r--r--services/backup/java/com/android/server/backup/internal/PerformBackupTask.java2
-rw-r--r--services/core/java/com/android/server/AppOpsService.java259
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java14
-rw-r--r--services/core/java/com/android/server/EventLogTags.logtags3
-rw-r--r--services/core/java/com/android/server/FgThread.java9
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java8
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java34
-rw-r--r--services/core/java/com/android/server/TextServicesManagerService.java13
-rw-r--r--services/core/java/com/android/server/UiThread.java4
-rw-r--r--services/core/java/com/android/server/Watchdog.java1
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java25
-rw-r--r--services/core/java/com/android/server/am/ActivityRecord.java4
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java9
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java28
-rw-r--r--services/core/java/com/android/server/am/ActivityStartController.java2
-rw-r--r--services/core/java/com/android/server/am/ActivityStartInterceptor.java17
-rw-r--r--services/core/java/com/android/server/am/ActivityStarter.java15
-rw-r--r--services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java24
-rw-r--r--services/core/java/com/android/server/content/ContentService.java4
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java6
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java2
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java15
-rw-r--r--services/core/java/com/android/server/fingerprint/ClientMonitor.java23
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java36
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java66
-rw-r--r--services/core/java/com/android/server/notification/RankingHelper.java70
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java25
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerService.java44
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerServiceImpl.java78
-rw-r--r--services/core/java/com/android/server/pm/InstantAppResolver.java7
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java26
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java8
-rw-r--r--services/core/java/com/android/server/pm/UserDataPreparer.java13
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java34
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java10
-rw-r--r--services/core/java/com/android/server/power/Notifier.java5
-rw-r--r--services/core/java/com/android/server/power/batterysaver/BatterySaverController.java32
-rw-r--r--services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java73
-rw-r--r--services/core/java/com/android/server/wm/AppWindowContainerController.java11
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java8
-rw-r--r--services/core/java/com/android/server/wm/DockedStackDividerController.java69
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java22
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java6
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp10
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java10
-rw-r--r--services/java/com/android/server/SystemServer.java5
-rw-r--r--services/net/java/android/net/ip/IpClient.java38
-rw-r--r--services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java51
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTest.java56
-rw-r--r--services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java110
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java3
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java74
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java84
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java11
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java130
-rw-r--r--services/usage/java/com/android/server/usage/AppStandbyController.java64
-rw-r--r--telephony/java/android/provider/Telephony.java18
-rw-r--r--telephony/java/android/telephony/PhoneStateListener.java2
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java10
-rw-r--r--telephony/java/com/android/ims/ImsConfig.java7
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyPermissions.java41
-rw-r--r--test-mock/src/android/test/mock/MockContext.java7
-rw-r--r--tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java2
-rw-r--r--tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java14
-rw-r--r--tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java6
-rw-r--r--tools/aapt2/ResourceParser.cpp9
-rw-r--r--tools/aapt2/ResourceParser_test.cpp20
-rw-r--r--tools/aapt2/format/binary/XmlFlattener.cpp22
-rw-r--r--tools/aapt2/format/binary/XmlFlattener_test.cpp159
-rw-r--r--tools/incident_section_gen/main.cpp3
422 files changed, 6268 insertions, 18092 deletions
diff --git a/Android.mk b/Android.mk
index 88394d6332b6..bb37fa21c463 100644
--- a/Android.mk
+++ b/Android.mk
@@ -448,6 +448,7 @@ LOCAL_DROIDDOC_OPTIONS:=\
-showAnnotation android.annotation.SystemApi \
-showAnnotation android.annotation.TestApi \
-privateDexApi $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE) \
+ -removedDexApi $(INTERNAL_PLATFORM_REMOVED_DEX_API_FILE) \
-nodocs
LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk
@@ -456,7 +457,8 @@ LOCAL_UNINSTALLABLE_MODULE := true
include $(BUILD_DROIDDOC)
-$(full_target): .KATI_IMPLICIT_OUTPUTS := $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE)
+$(full_target): .KATI_IMPLICIT_OUTPUTS := $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE) \
+ $(INTERNAL_PLATFORM_REMOVED_DEX_API_FILE)
# ==== check javadoc comments but don't generate docs ========
include $(CLEAR_VARS)
@@ -871,9 +873,16 @@ include $(BUILD_STATIC_JAVA_LIBRARY)
# rules for building them. Other rules in the build system should depend on the
# files in the build folder.
-# Automatically add all methods which match the following signatures.
-# These need to be greylisted in order to allow applications to write their
-# own serializers.
+# Merge light greylist from multiple files:
+# (1) manual light greylist
+# (2) list of usages from vendor apps
+# (3) list of removed APIs
+# @removed does not imply private in Doclava. We must take the subset also
+# in PRIVATE_API.
+# (4) list of serialization APIs
+# Automatically adds all methods which match the signatures in
+# REGEX_SERIALIZATION. These are greylisted in order to allow applications
+# to write their own serializers.
$(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST): REGEX_SERIALIZATION := \
"readObject\(Ljava/io/ObjectInputStream;\)V" \
"readObjectNoData\(\)V" \
@@ -883,14 +892,15 @@ $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST): REGEX_SERIALIZATION := \
"writeObject\(Ljava/io/ObjectOutputStream;\)V" \
"writeReplace\(\)Ljava/lang/Object;"
$(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST): PRIVATE_API := $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE)
-# Temporarily merge light greylist from two files. Vendor list will become dark
-# grey once we remove the UI toast.
+$(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST): REMOVED_API := $(INTERNAL_PLATFORM_REMOVED_DEX_API_FILE)
$(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST): frameworks/base/config/hiddenapi-light-greylist.txt \
frameworks/base/config/hiddenapi-vendor-list.txt \
- $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE)
+ $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE) \
+ $(INTERNAL_PLATFORM_REMOVED_DEX_API_FILE)
sort frameworks/base/config/hiddenapi-light-greylist.txt \
frameworks/base/config/hiddenapi-vendor-list.txt \
<(grep -E "\->("$(subst $(space),"|",$(REGEX_SERIALIZATION))")$$" $(PRIVATE_API)) \
+ <(comm -12 <(sort $(REMOVED_API)) <(sort $(PRIVATE_API))) \
> $@
$(eval $(call copy-one-file,frameworks/base/config/hiddenapi-dark-greylist.txt,\
diff --git a/api/current.txt b/api/current.txt
index 26e42982de91..8703bf41438b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -162,6 +162,7 @@ package android {
public static final class Manifest.permission_group {
ctor public Manifest.permission_group();
field public static final java.lang.String CALENDAR = "android.permission-group.CALENDAR";
+ field public static final java.lang.String CALL_LOG = "android.permission-group.CALL_LOG";
field public static final java.lang.String CAMERA = "android.permission-group.CAMERA";
field public static final java.lang.String CONTACTS = "android.permission-group.CONTACTS";
field public static final java.lang.String LOCATION = "android.permission-group.LOCATION";
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 93875cde4e24..e5bde0d83cf7 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -151,7 +151,8 @@ DONE:
}
// ================================================================================
-Section::Section(int i, const int64_t timeoutMs) : id(i), timeoutMs(timeoutMs) {}
+Section::Section(int i, int64_t timeoutMs, bool deviceSpecific)
+ : id(i), timeoutMs(timeoutMs), deviceSpecific(deviceSpecific) {}
Section::~Section() {}
@@ -236,8 +237,9 @@ status_t MetadataSection::Execute(ReportRequestSet* requests) const {
// ================================================================================
static inline bool isSysfs(const char* filename) { return strncmp(filename, "/sys/", 5) == 0; }
-FileSection::FileSection(int id, const char* filename, const int64_t timeoutMs)
- : Section(id, timeoutMs), mFilename(filename) {
+FileSection::FileSection(int id, const char* filename, const bool deviceSpecific,
+ const int64_t timeoutMs)
+ : Section(id, timeoutMs, deviceSpecific), mFilename(filename) {
name = filename;
mIsSysfs = isSysfs(filename);
}
@@ -250,7 +252,7 @@ status_t FileSection::Execute(ReportRequestSet* requests) const {
unique_fd fd(open(mFilename, O_RDONLY | O_CLOEXEC));
if (fd.get() == -1) {
ALOGW("FileSection '%s' failed to open file", this->name.string());
- return -errno;
+ return this->deviceSpecific ? NO_ERROR : -errno;
}
FdBuffer buffer;
@@ -902,11 +904,16 @@ status_t TombstoneSection::BlockingCall(int pipeWriteFd) const {
// Read from the pipe concurrently to avoid blocking the child.
FdBuffer buffer;
err = buffer.readFully(dumpPipe.readFd().get());
+ // Wait on the child to avoid it becoming a zombie process.
+ status_t cStatus = wait_child(child);
if (err != NO_ERROR) {
ALOGW("TombstoneSection '%s' failed to read stack dump: %d", this->name.string(), err);
dumpPipe.readFd().reset();
break;
}
+ if (cStatus != NO_ERROR) {
+ ALOGE("TombstoneSection '%s' child had an issue: %s\n", this->name.string(), strerror(-cStatus));
+ }
auto dump = std::make_unique<char[]>(buffer.size());
auto iterator = buffer.data();
diff --git a/cmds/incidentd/src/Section.h b/cmds/incidentd/src/Section.h
index 20ecdb1cdfbd..577892ef3a38 100644
--- a/cmds/incidentd/src/Section.h
+++ b/cmds/incidentd/src/Section.h
@@ -40,9 +40,10 @@ class Section {
public:
const int id;
const int64_t timeoutMs; // each section must have a timeout
+ const bool deviceSpecific;
String8 name;
- Section(int id, const int64_t timeoutMs = REMOTE_CALL_TIMEOUT_MS);
+ Section(int id, int64_t timeoutMs = REMOTE_CALL_TIMEOUT_MS, bool deviceSpecific = false);
virtual ~Section();
virtual status_t Execute(ReportRequestSet* requests) const = 0;
@@ -75,7 +76,8 @@ public:
*/
class FileSection : public Section {
public:
- FileSection(int id, const char* filename, const int64_t timeoutMs = 5000 /* 5 seconds */);
+ FileSection(int id, const char* filename, bool deviceSpecific = false,
+ int64_t timeoutMs = 5000 /* 5 seconds */);
virtual ~FileSection();
virtual status_t Execute(ReportRequestSet* requests) const;
@@ -105,7 +107,7 @@ private:
*/
class WorkerThreadSection : public Section {
public:
- WorkerThreadSection(int id, const int64_t timeoutMs = REMOTE_CALL_TIMEOUT_MS);
+ WorkerThreadSection(int id, int64_t timeoutMs = REMOTE_CALL_TIMEOUT_MS);
virtual ~WorkerThreadSection();
virtual status_t Execute(ReportRequestSet* requests) const;
@@ -118,7 +120,7 @@ public:
*/
class CommandSection : public Section {
public:
- CommandSection(int id, const int64_t timeoutMs, const char* command, ...);
+ CommandSection(int id, int64_t timeoutMs, const char* command, ...);
CommandSection(int id, const char* command, ...);
@@ -168,7 +170,7 @@ private:
*/
class TombstoneSection : public WorkerThreadSection {
public:
- TombstoneSection(int id, const char* type, const int64_t timeoutMs = 30000 /* 30 seconds */);
+ TombstoneSection(int id, const char* type, int64_t timeoutMs = 30000 /* 30 seconds */);
virtual ~TombstoneSection();
virtual status_t BlockingCall(int pipeWriteFd) const;
diff --git a/cmds/incidentd/tests/Section_test.cpp b/cmds/incidentd/tests/Section_test.cpp
index 33f520628356..3c338b3a36c8 100644
--- a/cmds/incidentd/tests/Section_test.cpp
+++ b/cmds/incidentd/tests/Section_test.cpp
@@ -143,8 +143,16 @@ TEST_F(SectionTest, FileSection) {
EXPECT_THAT(GetCapturedStdout(), StrEq("\xa\vatadtsetmai"));
}
+TEST_F(SectionTest, FileSectionNotExist) {
+ FileSection fs1(NOOP_PARSER, "notexist", false, QUICK_TIMEOUT_MS);
+ ASSERT_EQ(NAME_NOT_FOUND, fs1.Execute(&requests));
+
+ FileSection fs2(NOOP_PARSER, "notexist", true, QUICK_TIMEOUT_MS);
+ ASSERT_EQ(NO_ERROR, fs2.Execute(&requests));
+}
+
TEST_F(SectionTest, FileSectionTimeout) {
- FileSection fs(TIMEOUT_PARSER, tf.path, QUICK_TIMEOUT_MS);
+ FileSection fs(TIMEOUT_PARSER, tf.path, false, QUICK_TIMEOUT_MS);
ASSERT_EQ(NO_ERROR, fs.Execute(&requests));
ASSERT_TRUE(requests.sectionStats(TIMEOUT_PARSER)->timed_out());
}
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index b085a09a8608..7198bad9bedf 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -19,6 +19,7 @@ statsd_common_src := \
../../core/java/android/os/IStatsManager.aidl \
src/statsd_config.proto \
src/FieldValue.cpp \
+ src/hash.cpp \
src/stats_log_util.cpp \
src/anomaly/AlarmMonitor.cpp \
src/anomaly/AlarmTracker.cpp \
diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp
index dfd8705f83aa..f150f074c52b 100644
--- a/cmds/statsd/src/FieldValue.cpp
+++ b/cmds/statsd/src/FieldValue.cpp
@@ -237,6 +237,18 @@ bool HasPositionANY(const FieldMatcher& matcher) {
return false;
}
+bool HasPositionALL(const FieldMatcher& matcher) {
+ if (matcher.has_position() && matcher.position() == Position::ALL) {
+ return true;
+ }
+ for (const auto& child : matcher.child()) {
+ if (HasPositionALL(child)) {
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace statsd
} // namespace os
} // namespace android \ No newline at end of file
diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h
index f7ce23b04339..02c49b99c583 100644
--- a/cmds/statsd/src/FieldValue.h
+++ b/cmds/statsd/src/FieldValue.h
@@ -351,6 +351,7 @@ struct FieldValue {
};
bool HasPositionANY(const FieldMatcher& matcher);
+bool HasPositionALL(const FieldMatcher& matcher);
bool isAttributionUidField(const FieldValue& value);
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index d548c0a4fc65..986f2ef9a0a3 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -65,6 +65,7 @@ const int FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS = 4;
const int FIELD_ID_LAST_REPORT_WALL_CLOCK_NANOS = 5;
const int FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS = 6;
const int FIELD_ID_DUMP_REPORT_REASON = 8;
+const int FIELD_ID_STRINGS = 9;
#define NS_PER_HOUR 3600 * NS_PER_SEC
@@ -293,6 +294,7 @@ void StatsLogProcessor::dumpStates(FILE* out, bool verbose) {
*/
void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTimeStampNs,
const bool include_current_partial_bucket,
+ const bool include_string,
const DumpReportReason dumpReportReason,
vector<uint8_t>* outData) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
@@ -320,7 +322,7 @@ void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTim
uint64_t reportsToken =
proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS);
onConfigMetricsReportLocked(key, dumpTimeStampNs, include_current_partial_bucket,
- dumpReportReason, &proto);
+ include_string, dumpReportReason, &proto);
proto.end(reportsToken);
// End of ConfigMetricsReport (reports).
} else {
@@ -349,6 +351,7 @@ void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTim
void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key,
const int64_t dumpTimeStampNs,
const bool include_current_partial_bucket,
+ const bool include_string,
const DumpReportReason dumpReportReason,
ProtoOutputStream* proto) {
// We already checked whether key exists in mMetricsManagers in
@@ -360,13 +363,16 @@ void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key,
int64_t lastReportTimeNs = it->second->getLastReportTimeNs();
int64_t lastReportWallClockNs = it->second->getLastReportWallClockNs();
+ std::set<string> str_set;
+
// First, fill in ConfigMetricsReport using current data on memory, which
// starts from filling in StatsLogReport's.
- it->second->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, proto);
+ it->second->onDumpReport(dumpTimeStampNs, include_current_partial_bucket,
+ &str_set, proto);
// Fill in UidMap.
uint64_t uidMapToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP);
- mUidMap->appendUidMap(dumpTimeStampNs, key, proto);
+ mUidMap->appendUidMap(dumpTimeStampNs, key, &str_set, proto);
proto->end(uidMapToken);
// Fill in the timestamps.
@@ -380,6 +386,12 @@ void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key,
(long long)getWallClockNs());
// Dump report reason
proto->write(FIELD_TYPE_INT32 | FIELD_ID_DUMP_REPORT_REASON, dumpReportReason);
+
+ if (include_string) {
+ for (const auto& str : str_set) {
+ proto->write(FIELD_TYPE_STRING | FIELD_COUNT_REPEATED | FIELD_ID_STRINGS, str);
+ }
+ }
}
void StatsLogProcessor::resetConfigsLocked(const int64_t timestampNs,
@@ -465,7 +477,8 @@ void StatsLogProcessor::WriteDataToDiskLocked(const ConfigKey& key,
const DumpReportReason dumpReportReason) {
ProtoOutputStream proto;
onConfigMetricsReportLocked(key, getElapsedRealtimeNs(),
- true /* include_current_partial_bucket*/, dumpReportReason, &proto);
+ true /* include_current_partial_bucket*/,
+ false /* include strings */, dumpReportReason, &proto);
string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR,
(long)getWallClockSec(), key.GetUid(), (long long)key.GetId());
android::base::unique_fd fd(open(file_name.c_str(),
@@ -489,6 +502,7 @@ void StatsLogProcessor::WriteDataToDisk(bool isShutdown) {
}
void StatsLogProcessor::informPullAlarmFired(const int64_t timestampNs) {
+ std::lock_guard<std::mutex> lock(mMetricsMutex);
mStatsPullerManager.OnAlarmFired(timestampNs);
}
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index c2337c147740..c3c4663ed433 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -63,7 +63,7 @@ public:
size_t GetMetricsSize(const ConfigKey& key) const;
void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs,
- const bool include_current_partial_bucket,
+ const bool include_current_partial_bucket, const bool include_string,
const DumpReportReason dumpReportReason, vector<uint8_t>* outData);
/* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */
@@ -126,6 +126,7 @@ private:
void onConfigMetricsReportLocked(const ConfigKey& key, const int64_t dumpTimeStampNs,
const bool include_current_partial_bucket,
+ const bool include_string,
const DumpReportReason dumpReportReason,
util::ProtoOutputStream* proto);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 5229071d8df3..0e7b4f9ba49f 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -592,7 +592,8 @@ status_t StatsService::cmd_dump_report(FILE* out, FILE* err, const Vector<String
if (good) {
vector<uint8_t> data;
mProcessor->onDumpReport(ConfigKey(uid, StrToInt64(name)), getElapsedRealtimeNs(),
- false /* include_current_bucket*/, ADB_DUMP, &data);
+ false /* include_current_bucket*/,
+ true /* include strings */, ADB_DUMP, &data);
// TODO: print the returned StatsLogReport to file instead of printing to logcat.
if (proto) {
for (size_t i = 0; i < data.size(); i ++) {
@@ -865,8 +866,9 @@ Status StatsService::getData(int64_t key, const String16& packageName, vector<ui
IPCThreadState* ipc = IPCThreadState::self();
VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
ConfigKey configKey(ipc->getCallingUid(), key);
- mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(), false /* include_current_bucket*/,
- GET_DATA_CALLED, output);
+ mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(),
+ false /* include_current_bucket*/, true /* include strings */,
+ GET_DATA_CALLED, output);
return Status::ok();
}
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 2cbcca3ed95e..65ba4f7b12f7 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -114,7 +114,7 @@ public:
// Soft memory limit per configuration. Once this limit is exceeded, we begin notifying the
// data subscriber that it's time to call getData.
- static const size_t kBytesPerConfigTriggerGetData = 128 * 1024;
+ static const size_t kBytesPerConfigTriggerGetData = 192 * 1024;
// Cap the UID map's memory usage to this. This should be fairly high since the UID information
// is critical for understanding the metrics.
diff --git a/cmds/statsd/src/hash.cpp b/cmds/statsd/src/hash.cpp
new file mode 100644
index 000000000000..c501c9f818b9
--- /dev/null
+++ b/cmds/statsd/src/hash.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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 "hash.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+namespace {
+// Lower-level versions of Get... that read directly from a character buffer
+// without any bounds checking.
+inline uint32_t DecodeFixed32(const char *ptr) {
+ return ((static_cast<uint32_t>(static_cast<unsigned char>(ptr[0]))) |
+ (static_cast<uint32_t>(static_cast<unsigned char>(ptr[1])) << 8) |
+ (static_cast<uint32_t>(static_cast<unsigned char>(ptr[2])) << 16) |
+ (static_cast<uint32_t>(static_cast<unsigned char>(ptr[3])) << 24));
+}
+
+inline uint64_t DecodeFixed64(const char* ptr) {
+ uint64_t lo = DecodeFixed32(ptr);
+ uint64_t hi = DecodeFixed32(ptr + 4);
+ return (hi << 32) | lo;
+}
+
+// 0xff is in case char is signed.
+static inline uint32_t ByteAs32(char c) { return static_cast<uint32_t>(c) & 0xff; }
+static inline uint64_t ByteAs64(char c) { return static_cast<uint64_t>(c) & 0xff; }
+
+} // namespace
+
+uint32_t Hash32(const char *data, size_t n, uint32_t seed) {
+ // 'm' and 'r' are mixing constants generated offline.
+ // They're not really 'magic', they just happen to work well.
+ const uint32_t m = 0x5bd1e995;
+ const int r = 24;
+
+ // Initialize the hash to a 'random' value
+ uint32_t h = static_cast<uint32_t>(seed ^ n);
+
+ // Mix 4 bytes at a time into the hash
+ while (n >= 4) {
+ uint32_t k = DecodeFixed32(data);
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+ h *= m;
+ h ^= k;
+ data += 4;
+ n -= 4;
+ }
+
+ // Handle the last few bytes of the input array
+ switch (n) {
+ case 3:
+ h ^= ByteAs32(data[2]) << 16;
+ case 2:
+ h ^= ByteAs32(data[1]) << 8;
+ case 1:
+ h ^= ByteAs32(data[0]);
+ h *= m;
+ }
+
+ // Do a few final mixes of the hash to ensure the last few
+ // bytes are well-incorporated.
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+ return h;
+}
+
+uint64_t Hash64(const char* data, size_t n, uint64_t seed) {
+ const uint64_t m = 0xc6a4a7935bd1e995;
+ const int r = 47;
+
+ uint64_t h = seed ^ (n * m);
+
+ while (n >= 8) {
+ uint64_t k = DecodeFixed64(data);
+ data += 8;
+ n -= 8;
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h ^= k;
+ h *= m;
+ }
+
+ switch (n) {
+ case 7:
+ h ^= ByteAs64(data[6]) << 48;
+ case 6:
+ h ^= ByteAs64(data[5]) << 40;
+ case 5:
+ h ^= ByteAs64(data[4]) << 32;
+ case 4:
+ h ^= ByteAs64(data[3]) << 24;
+ case 3:
+ h ^= ByteAs64(data[2]) << 16;
+ case 2:
+ h ^= ByteAs64(data[1]) << 8;
+ case 1:
+ h ^= ByteAs64(data[0]);
+ h *= m;
+ }
+
+ h ^= h >> r;
+ h *= m;
+ h ^= h >> r;
+
+ return h;
+}
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/hash.h b/cmds/statsd/src/hash.h
new file mode 100644
index 000000000000..cfe869f60202
--- /dev/null
+++ b/cmds/statsd/src/hash.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+extern uint32_t Hash32(const char *data, size_t n, uint32_t seed);
+extern uint64_t Hash64(const char* data, size_t n, uint64_t seed);
+
+inline uint32_t Hash32(const char *data, size_t n) {
+ return Hash32(data, n, 0xBEEF);
+}
+
+inline uint32_t Hash32(const std::string &input) {
+ return Hash32(input.data(), input.size());
+}
+
+inline uint64_t Hash64(const char* data, size_t n) {
+ return Hash64(data, n, 0xDECAFCAFFE);
+}
+
+inline uint64_t Hash64(const std::string& str) {
+ return Hash64(str.data(), str.size());
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index e21392cb8ce6..43f53e057000 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -45,16 +45,23 @@ namespace statsd {
// for StatsLogReport
const int FIELD_ID_ID = 1;
const int FIELD_ID_COUNT_METRICS = 5;
+const int FIELD_ID_TIME_BASE = 9;
+const int FIELD_ID_BUCKET_SIZE = 10;
+const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
+const int FIELD_ID_DIMENSION_PATH_IN_CONDITION = 12;
// for CountMetricDataWrapper
const int FIELD_ID_DATA = 1;
// for CountMetricData
const int FIELD_ID_DIMENSION_IN_WHAT = 1;
const int FIELD_ID_DIMENSION_IN_CONDITION = 2;
const int FIELD_ID_BUCKET_INFO = 3;
+const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4;
+const int FIELD_ID_DIMENSION_LEAF_IN_CONDITION = 5;
// for CountBucketInfo
-const int FIELD_ID_START_BUCKET_ELAPSED_NANOS = 1;
-const int FIELD_ID_END_BUCKET_ELAPSED_NANOS = 2;
const int FIELD_ID_COUNT = 3;
+const int FIELD_ID_BUCKET_NUM = 4;
+const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 5;
+const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
CountMetricProducer::CountMetricProducer(const ConfigKey& key, const CountMetric& metric,
const int conditionIndex,
@@ -74,6 +81,9 @@ CountMetricProducer::CountMetricProducer(const ConfigKey& key, const CountMetric
mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
}
+ mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what()) ||
+ HasPositionALL(metric.dimensions_in_condition());
+
if (metric.has_dimensions_in_condition()) {
translateFieldMatcher(metric.dimensions_in_condition(), &mDimensionsInCondition);
}
@@ -122,8 +132,15 @@ void CountMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition
VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
}
+
+void CountMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
+ flushIfNeededLocked(dumpTimeNs);
+ mPastBuckets.clear();
+}
+
void CountMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
if (include_current_partial_bucket) {
flushLocked(dumpTimeNs);
@@ -134,6 +151,26 @@ void CountMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
return;
}
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TIME_BASE, (long long)mTimeBaseNs);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_SIZE, (long long)mBucketSizeNs);
+
+ // Fills the dimension path if not slicing by ALL.
+ if (!mSliceByPositionALL) {
+ if (!mDimensionsInWhat.empty()) {
+ uint64_t dimenPathToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_WHAT);
+ writeDimensionPathToProto(mDimensionsInWhat, protoOutput);
+ protoOutput->end(dimenPathToken);
+ }
+ if (!mDimensionsInCondition.empty()) {
+ uint64_t dimenPathToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_CONDITION);
+ writeDimensionPathToProto(mDimensionsInCondition, protoOutput);
+ protoOutput->end(dimenPathToken);
+ }
+
+ }
+
uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_COUNT_METRICS);
for (const auto& counter : mPastBuckets) {
@@ -144,27 +181,42 @@ void CountMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
// First fill dimension.
- uint64_t dimensionInWhatToken = protoOutput->start(
- FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
- writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), protoOutput);
- protoOutput->end(dimensionInWhatToken);
-
- if (dimensionKey.hasDimensionKeyInCondition()) {
- uint64_t dimensionInConditionToken = protoOutput->start(
- FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
- writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), protoOutput);
- protoOutput->end(dimensionInConditionToken);
+ if (mSliceByPositionALL) {
+ uint64_t dimensionToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
+ writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput);
+ protoOutput->end(dimensionToken);
+
+ if (dimensionKey.hasDimensionKeyInCondition()) {
+ uint64_t dimensionInConditionToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
+ writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(),
+ str_set, protoOutput);
+ protoOutput->end(dimensionInConditionToken);
+ }
+ } else {
+ writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(),
+ FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
+ if (dimensionKey.hasDimensionKeyInCondition()) {
+ writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInCondition(),
+ FIELD_ID_DIMENSION_LEAF_IN_CONDITION,
+ str_set, protoOutput);
+ }
}
-
// Then fill bucket_info (CountBucketInfo).
-
for (const auto& bucket : counter.second) {
uint64_t bucketInfoToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_NANOS,
- (long long)bucket.mBucketStartNs);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_NANOS,
- (long long)bucket.mBucketEndNs);
+ // Partial bucket.
+ if (bucket.mBucketEndNs - bucket.mBucketStartNs != mBucketSizeNs) {
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_MILLIS,
+ (long long)NanoToMillis(bucket.mBucketStartNs));
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_MILLIS,
+ (long long)NanoToMillis(bucket.mBucketEndNs));
+ } else {
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_NUM,
+ (long long)(getBucketNumFromEndTimeNs(bucket.mBucketEndNs)));
+ }
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_COUNT, (long long)bucket.mCount);
protoOutput->end(bucketInfoToken);
VLOG("\t bucket [%lld - %lld] count: %lld", (long long)bucket.mBucketStartNs,
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index cafc882308d4..139c0838fef0 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -57,8 +57,11 @@ private:
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) override;
+ void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
+
// Internal interface to handle condition change.
void onConditionChangedLocked(const bool conditionMet, const int64_t eventTime) override;
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 3661b31d9ee4..62237bc04642 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -44,16 +44,23 @@ namespace statsd {
// for StatsLogReport
const int FIELD_ID_ID = 1;
const int FIELD_ID_DURATION_METRICS = 6;
+const int FIELD_ID_TIME_BASE = 9;
+const int FIELD_ID_BUCKET_SIZE = 10;
+const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
+const int FIELD_ID_DIMENSION_PATH_IN_CONDITION = 12;
// for DurationMetricDataWrapper
const int FIELD_ID_DATA = 1;
// for DurationMetricData
const int FIELD_ID_DIMENSION_IN_WHAT = 1;
const int FIELD_ID_DIMENSION_IN_CONDITION = 2;
const int FIELD_ID_BUCKET_INFO = 3;
+const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4;
+const int FIELD_ID_DIMENSION_LEAF_IN_CONDITION = 5;
// for DurationBucketInfo
-const int FIELD_ID_START_BUCKET_ELAPSED_NANOS = 1;
-const int FIELD_ID_END_BUCKET_ELAPSED_NANOS = 2;
const int FIELD_ID_DURATION = 3;
+const int FIELD_ID_BUCKET_NUM = 4;
+const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 5;
+const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
DurationMetricProducer::DurationMetricProducer(const ConfigKey& key, const DurationMetric& metric,
const int conditionIndex, const size_t startIndex,
@@ -99,6 +106,9 @@ DurationMetricProducer::DurationMetricProducer(const ConfigKey& key, const Durat
translateFieldMatcher(metric.dimensions_in_condition(), &mDimensionsInCondition);
}
+ mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what()) ||
+ HasPositionALL(metric.dimensions_in_condition());
+
if (metric.links().size() > 0) {
for (const auto& link : metric.links()) {
Metric2Condition mc;
@@ -438,8 +448,14 @@ void DurationMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
mPastBuckets.clear();
}
+void DurationMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
+ flushIfNeededLocked(dumpTimeNs);
+ mPastBuckets.clear();
+}
+
void DurationMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
if (include_current_partial_bucket) {
flushLocked(dumpTimeNs);
@@ -452,6 +468,24 @@ void DurationMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
}
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TIME_BASE, (long long)mTimeBaseNs);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_SIZE, (long long)mBucketSizeNs);
+
+ if (!mSliceByPositionALL) {
+ if (!mDimensionsInWhat.empty()) {
+ uint64_t dimenPathToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_WHAT);
+ writeDimensionPathToProto(mDimensionsInWhat, protoOutput);
+ protoOutput->end(dimenPathToken);
+ }
+ if (!mDimensionsInCondition.empty()) {
+ uint64_t dimenPathToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_CONDITION);
+ writeDimensionPathToProto(mDimensionsInCondition, protoOutput);
+ protoOutput->end(dimenPathToken);
+ }
+ }
+
uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DURATION_METRICS);
VLOG("Duration metric %lld dump report now...", (long long)mMetricId);
@@ -464,26 +498,41 @@ void DurationMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
// First fill dimension.
- uint64_t dimensionToken = protoOutput->start(
- FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
- writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), protoOutput);
- protoOutput->end(dimensionToken);
-
- if (dimensionKey.hasDimensionKeyInCondition()) {
- uint64_t dimensionInConditionToken = protoOutput->start(
- FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
- writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), protoOutput);
- protoOutput->end(dimensionInConditionToken);
+ if (mSliceByPositionALL) {
+ uint64_t dimensionToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
+ writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput);
+ protoOutput->end(dimensionToken);
+
+ if (dimensionKey.hasDimensionKeyInCondition()) {
+ uint64_t dimensionInConditionToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
+ writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(),
+ str_set, protoOutput);
+ protoOutput->end(dimensionInConditionToken);
+ }
+ } else {
+ writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(),
+ FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
+ if (dimensionKey.hasDimensionKeyInCondition()) {
+ writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInCondition(),
+ FIELD_ID_DIMENSION_LEAF_IN_CONDITION,
+ str_set, protoOutput);
+ }
}
-
// Then fill bucket_info (DurationBucketInfo).
for (const auto& bucket : pair.second) {
uint64_t bucketInfoToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_NANOS,
- (long long)bucket.mBucketStartNs);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_NANOS,
- (long long)bucket.mBucketEndNs);
+ if (bucket.mBucketEndNs - bucket.mBucketStartNs != mBucketSizeNs) {
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_MILLIS,
+ (long long)NanoToMillis(bucket.mBucketStartNs));
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_MILLIS,
+ (long long)NanoToMillis(bucket.mBucketEndNs));
+ } else {
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_NUM,
+ (long long)(getBucketNumFromEndTimeNs(bucket.mBucketEndNs)));
+ }
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DURATION, (long long)bucket.mDuration);
protoOutput->end(bucketInfoToken);
VLOG("\t bucket [%lld - %lld] duration: %lld", (long long)bucket.mBucketStartNs,
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 80fbdde2df09..88e455a3f1a1 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -63,8 +63,11 @@ private:
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) override;
+ void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
+
// Internal interface to handle condition change.
void onConditionChangedLocked(const bool conditionMet, const int64_t eventTime) override;
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 2f2679efab65..eec90fc8d053 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -100,8 +100,13 @@ std::unique_ptr<std::vector<uint8_t>> serializeProtoLocked(ProtoOutputStream& pr
return buffer;
}
+void EventMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
+ mProto->clear();
+}
+
void EventMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
if (mProto->size() <= 0) {
return;
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 5c2917400b10..62d1105e0514 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -48,7 +48,9 @@ private:
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) override;
+ void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
// Internal interface to handle condition change.
void onConditionChangedLocked(const bool conditionMet, const int64_t eventTime) override;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 12708567043b..a940d58b7c4d 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -45,21 +45,28 @@ namespace statsd {
// for StatsLogReport
const int FIELD_ID_ID = 1;
const int FIELD_ID_GAUGE_METRICS = 8;
+const int FIELD_ID_TIME_BASE = 9;
+const int FIELD_ID_BUCKET_SIZE = 10;
+const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
+const int FIELD_ID_DIMENSION_PATH_IN_CONDITION = 12;
// for GaugeMetricDataWrapper
const int FIELD_ID_DATA = 1;
const int FIELD_ID_SKIPPED = 2;
-const int FIELD_ID_SKIPPED_START = 1;
-const int FIELD_ID_SKIPPED_END = 2;
+const int FIELD_ID_SKIPPED_START_MILLIS = 3;
+const int FIELD_ID_SKIPPED_END_MILLIS = 4;
// for GaugeMetricData
const int FIELD_ID_DIMENSION_IN_WHAT = 1;
const int FIELD_ID_DIMENSION_IN_CONDITION = 2;
const int FIELD_ID_BUCKET_INFO = 3;
+const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4;
+const int FIELD_ID_DIMENSION_LEAF_IN_CONDITION = 5;
// for GaugeBucketInfo
-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_ELAPSED_ATOM_TIMESTAMP = 4;
const int FIELD_ID_WALL_CLOCK_ATOM_TIMESTAMP = 5;
+const int FIELD_ID_BUCKET_NUM = 6;
+const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 7;
+const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 8;
GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& metric,
const int conditionIndex,
@@ -113,6 +120,8 @@ GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric
}
}
mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
+ mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what()) ||
+ HasPositionALL(metric.dimensions_in_condition());
flushIfNeededLocked(startTimeNs);
// Kicks off the puller immediately.
@@ -160,8 +169,15 @@ void GaugeMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
}
}
+void GaugeMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
+ flushIfNeededLocked(dumpTimeNs);
+ mPastBuckets.clear();
+ mSkippedBuckets.clear();
+}
+
void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
VLOG("Gauge metric %lld report now...", (long long)mMetricId);
if (include_current_partial_bucket) {
@@ -176,13 +192,34 @@ void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
}
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TIME_BASE, (long long)mTimeBaseNs);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_SIZE, (long long)mBucketSizeNs);
+
+ // Fills the dimension path if not slicing by ALL.
+ if (!mSliceByPositionALL) {
+ if (!mDimensionsInWhat.empty()) {
+ uint64_t dimenPathToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_WHAT);
+ writeDimensionPathToProto(mDimensionsInWhat, protoOutput);
+ protoOutput->end(dimenPathToken);
+ }
+ if (!mDimensionsInCondition.empty()) {
+ uint64_t dimenPathToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_CONDITION);
+ writeDimensionPathToProto(mDimensionsInCondition, protoOutput);
+ protoOutput->end(dimenPathToken);
+ }
+ }
+
uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_GAUGE_METRICS);
for (const auto& pair : mSkippedBuckets) {
uint64_t wrapperToken =
protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_SKIPPED);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_START, (long long)pair.first);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_END, (long long)pair.second);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_START_MILLIS,
+ (long long)(NanoToMillis(pair.first)));
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_END_MILLIS,
+ (long long)(NanoToMillis(pair.second)));
protoOutput->end(wrapperToken);
}
mSkippedBuckets.clear();
@@ -195,26 +232,43 @@ void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
// First fill dimension.
- uint64_t dimensionToken = protoOutput->start(
- FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
- writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), protoOutput);
- protoOutput->end(dimensionToken);
-
- if (dimensionKey.hasDimensionKeyInCondition()) {
- uint64_t dimensionInConditionToken = protoOutput->start(
- FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
- writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), protoOutput);
- protoOutput->end(dimensionInConditionToken);
+ if (mSliceByPositionALL) {
+ uint64_t dimensionToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
+ writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput);
+ protoOutput->end(dimensionToken);
+
+ if (dimensionKey.hasDimensionKeyInCondition()) {
+ uint64_t dimensionInConditionToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
+ writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(),
+ str_set, protoOutput);
+ protoOutput->end(dimensionInConditionToken);
+ }
+ } else {
+ writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(),
+ FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
+ if (dimensionKey.hasDimensionKeyInCondition()) {
+ writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInCondition(),
+ FIELD_ID_DIMENSION_LEAF_IN_CONDITION,
+ str_set, protoOutput);
+ }
}
// Then fill bucket_info (GaugeBucketInfo).
for (const auto& bucket : pair.second) {
uint64_t bucketInfoToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_NANOS,
- (long long)bucket.mBucketStartNs);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_NANOS,
- (long long)bucket.mBucketEndNs);
+
+ if (bucket.mBucketEndNs - bucket.mBucketStartNs != mBucketSizeNs) {
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_MILLIS,
+ (long long)NanoToMillis(bucket.mBucketStartNs));
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_MILLIS,
+ (long long)NanoToMillis(bucket.mBucketEndNs));
+ } else {
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_NUM,
+ (long long)(getBucketNumFromEndTimeNs(bucket.mBucketEndNs)));
+ }
if (!bucket.mGaugeAtoms.empty()) {
for (const auto& atom : bucket.mGaugeAtoms) {
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 71d5912df6ae..ac2bd77f0df5 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -90,7 +90,9 @@ protected:
private:
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) override;
+ void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
// for testing
GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& gaugeMetric,
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 532ecbf36d72..6fe4bfb47a1f 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -52,6 +52,7 @@ public:
mWizard(wizard),
mConditionTrackerIndex(conditionIndex),
mContainANYPositionInDimensionsInWhat(false),
+ mSliceByPositionALL(false),
mSameConditionDimensionsInTracker(false),
mHasLinksToAllConditionDimensionsInTracker(false) {
}
@@ -114,9 +115,15 @@ public:
// This method clears all the past buckets.
void onDumpReport(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) {
std::lock_guard<std::mutex> lock(mMutex);
- return onDumpReportLocked(dumpTimeNs, include_current_partial_bucket, protoOutput);
+ return onDumpReportLocked(dumpTimeNs, include_current_partial_bucket, str_set, protoOutput);
+ }
+
+ void clearPastBuckets(const int64_t dumpTimeNs) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return clearPastBucketsLocked(dumpTimeNs);
}
void dumpStates(FILE* out, bool verbose) const {
@@ -176,7 +183,9 @@ protected:
const int64_t eventTime) = 0;
virtual void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) = 0;
+ virtual void clearPastBucketsLocked(const int64_t dumpTimeNs) = 0;
virtual size_t byteSizeLocked() const = 0;
virtual void dumpStatesLocked(FILE* out, bool verbose) const = 0;
@@ -212,6 +221,10 @@ protected:
return mTimeBaseNs + (mCurrentBucketNum + 1) * mBucketSizeNs;
}
+ int64_t getBucketNumFromEndTimeNs(const int64_t endNs) {
+ return (endNs - mTimeBaseNs) / mBucketSizeNs - 1;
+ }
+
virtual void dropDataLocked(const int64_t dropTimeNs) = 0;
const int64_t mMetricId;
@@ -244,6 +257,7 @@ protected:
vector<Matcher> mDimensionsInCondition; // The dimensions_in_condition defined in statsd_config
bool mContainANYPositionInDimensionsInWhat;
+ bool mSliceByPositionALL;
// True iff the condition dimensions equal to the sliced dimensions in the simple condition
// tracker. This field is always false for combinational condition trackers.
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 47a1a86f861f..9ca4daa755f6 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -36,6 +36,7 @@ using android::util::FIELD_COUNT_REPEATED;
using android::util::FIELD_TYPE_INT32;
using android::util::FIELD_TYPE_INT64;
using android::util::FIELD_TYPE_MESSAGE;
+using android::util::FIELD_TYPE_STRING;
using android::util::ProtoOutputStream;
using std::make_unique;
@@ -192,15 +193,19 @@ void MetricsManager::dropData(const int64_t dropTimeNs) {
void MetricsManager::onDumpReport(const int64_t dumpTimeStampNs,
const bool include_current_partial_bucket,
+ std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
VLOG("=========================Metric Reports Start==========================");
// one StatsLogReport per MetricProduer
for (const auto& producer : mAllMetricProducers) {
if (mNoReportMetricIds.find(producer->getMetricId()) == mNoReportMetricIds.end()) {
- uint64_t token =
- protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS);
- producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, protoOutput);
+ uint64_t token = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS);
+ producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, str_set,
+ protoOutput);
protoOutput->end(token);
+ } else {
+ producer->clearPastBuckets(dumpTimeStampNs);
}
}
for (const auto& annotation : mAnnotations) {
@@ -211,6 +216,7 @@ void MetricsManager::onDumpReport(const int64_t dumpTimeStampNs,
protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_ANNOTATIONS_INT32, annotation.second);
protoOutput->end(token);
}
+
mLastReportTimeNs = dumpTimeStampNs;
mLastReportWallClockNs = getWallClockNs();
VLOG("=========================Metric Reports End==========================");
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 3d2c5956df40..170d6a7eacae 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -92,6 +92,7 @@ public:
virtual void onDumpReport(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput);
// Computes the total byte size of all metrics managed by a single config source.
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 27fd78f4ed94..69330ba2a0c7 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -48,19 +48,26 @@ namespace statsd {
// for StatsLogReport
const int FIELD_ID_ID = 1;
const int FIELD_ID_VALUE_METRICS = 7;
+const int FIELD_ID_TIME_BASE = 9;
+const int FIELD_ID_BUCKET_SIZE = 10;
+const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
+const int FIELD_ID_DIMENSION_PATH_IN_CONDITION = 12;
// for ValueMetricDataWrapper
const int FIELD_ID_DATA = 1;
const int FIELD_ID_SKIPPED = 2;
-const int FIELD_ID_SKIPPED_START = 1;
-const int FIELD_ID_SKIPPED_END = 2;
+const int FIELD_ID_SKIPPED_START_MILLIS = 3;
+const int FIELD_ID_SKIPPED_END_MILLIS = 4;
// for ValueMetricData
const int FIELD_ID_DIMENSION_IN_WHAT = 1;
const int FIELD_ID_DIMENSION_IN_CONDITION = 2;
const int FIELD_ID_BUCKET_INFO = 3;
+const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4;
+const int FIELD_ID_DIMENSION_LEAF_IN_CONDITION = 5;
// for ValueBucketInfo
-const int FIELD_ID_START_BUCKET_NANOS = 1;
-const int FIELD_ID_END_BUCKET_NANOS = 2;
const int FIELD_ID_VALUE = 3;
+const int FIELD_ID_BUCKET_NUM = 4;
+const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 5;
+const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
// ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently
ValueMetricProducer::ValueMetricProducer(const ConfigKey& key, const ValueMetric& metric,
@@ -113,6 +120,8 @@ ValueMetricProducer::ValueMetricProducer(const ConfigKey& key, const ValueMetric
mField = mValueField.child(0).field();
}
mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
+ mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what()) ||
+ HasPositionALL(metric.dimensions_in_condition());
// Kicks off the puller immediately.
flushIfNeededLocked(startTimestampNs);
@@ -151,8 +160,15 @@ void ValueMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
mPastBuckets.clear();
}
+void ValueMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
+ flushIfNeededLocked(dumpTimeNs);
+ mPastBuckets.clear();
+ mSkippedBuckets.clear();
+}
+
void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
VLOG("metric %lld dump report now...", (long long)mMetricId);
if (include_current_partial_bucket) {
@@ -164,13 +180,33 @@ void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
return;
}
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TIME_BASE, (long long)mTimeBaseNs);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_SIZE, (long long)mBucketSizeNs);
+ // Fills the dimension path if not slicing by ALL.
+ if (!mSliceByPositionALL) {
+ if (!mDimensionsInWhat.empty()) {
+ uint64_t dimenPathToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_WHAT);
+ writeDimensionPathToProto(mDimensionsInWhat, protoOutput);
+ protoOutput->end(dimenPathToken);
+ }
+ if (!mDimensionsInCondition.empty()) {
+ uint64_t dimenPathToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_CONDITION);
+ writeDimensionPathToProto(mDimensionsInCondition, protoOutput);
+ protoOutput->end(dimenPathToken);
+ }
+ }
+
uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_VALUE_METRICS);
for (const auto& pair : mSkippedBuckets) {
uint64_t wrapperToken =
protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_SKIPPED);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_START, (long long)pair.first);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_END, (long long)pair.second);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_START_MILLIS,
+ (long long)(NanoToMillis(pair.first)));
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_END_MILLIS,
+ (long long)(NanoToMillis(pair.second)));
protoOutput->end(wrapperToken);
}
mSkippedBuckets.clear();
@@ -182,25 +218,43 @@ void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
// First fill dimension.
- uint64_t dimensionToken = protoOutput->start(
- FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
- writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), protoOutput);
- protoOutput->end(dimensionToken);
- if (dimensionKey.hasDimensionKeyInCondition()) {
- uint64_t dimensionInConditionToken = protoOutput->start(
- FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
- writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), protoOutput);
- protoOutput->end(dimensionInConditionToken);
+ if (mSliceByPositionALL) {
+ uint64_t dimensionToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
+ writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput);
+ protoOutput->end(dimensionToken);
+ if (dimensionKey.hasDimensionKeyInCondition()) {
+ uint64_t dimensionInConditionToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
+ writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(),
+ str_set, protoOutput);
+ protoOutput->end(dimensionInConditionToken);
+ }
+ } else {
+ writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(),
+ FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
+ if (dimensionKey.hasDimensionKeyInCondition()) {
+ writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInCondition(),
+ FIELD_ID_DIMENSION_LEAF_IN_CONDITION,
+ str_set, protoOutput);
+ }
}
// Then fill bucket_info (ValueBucketInfo).
for (const auto& bucket : pair.second) {
uint64_t bucketInfoToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
- (long long)bucket.mBucketStartNs);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
- (long long)bucket.mBucketEndNs);
+
+ if (bucket.mBucketEndNs - bucket.mBucketStartNs != mBucketSizeNs) {
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_MILLIS,
+ (long long)NanoToMillis(bucket.mBucketStartNs));
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_MILLIS,
+ (long long)NanoToMillis(bucket.mBucketEndNs));
+ } else {
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_NUM,
+ (long long)(getBucketNumFromEndTimeNs(bucket.mBucketEndNs)));
+ }
+
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE, (long long)bucket.mValue);
protoOutput->end(bucketInfoToken);
VLOG("\t bucket [%lld - %lld] count: %lld", (long long)bucket.mBucketStartNs,
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 8df30d3de284..113be4b39944 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -88,7 +88,9 @@ protected:
private:
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) override;
+ void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
// Internal interface to handle condition change.
void onConditionChangedLocked(const bool conditionMet, const int64_t eventTime) override;
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 26741716cc22..fff909c12441 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -16,6 +16,7 @@
#define DEBUG false // STOPSHIP if true
#include "Log.h"
+#include "hash.h"
#include "stats_log_util.h"
#include "guardrail/StatsdStats.h"
#include "packages/UidMap.h"
@@ -34,6 +35,7 @@ using android::util::FIELD_TYPE_BOOL;
using android::util::FIELD_TYPE_FLOAT;
using android::util::FIELD_TYPE_INT32;
using android::util::FIELD_TYPE_INT64;
+using android::util::FIELD_TYPE_UINT64;
using android::util::FIELD_TYPE_MESSAGE;
using android::util::FIELD_TYPE_STRING;
using android::util::ProtoOutputStream;
@@ -46,6 +48,7 @@ const int FIELD_ID_SNAPSHOT_PACKAGE_NAME = 1;
const int FIELD_ID_SNAPSHOT_PACKAGE_VERSION = 2;
const int FIELD_ID_SNAPSHOT_PACKAGE_UID = 3;
const int FIELD_ID_SNAPSHOT_PACKAGE_DELETED = 4;
+const int FIELD_ID_SNAPSHOT_PACKAGE_NAME_HASH = 5;
const int FIELD_ID_SNAPSHOT_TIMESTAMP = 1;
const int FIELD_ID_SNAPSHOT_PACKAGE_INFO = 2;
const int FIELD_ID_SNAPSHOTS = 1;
@@ -56,6 +59,7 @@ const int FIELD_ID_CHANGE_PACKAGE = 3;
const int FIELD_ID_CHANGE_UID = 4;
const int FIELD_ID_CHANGE_NEW_VERSION = 5;
const int FIELD_ID_CHANGE_PREV_VERSION = 6;
+const int FIELD_ID_CHANGE_PACKAGE_HASH = 7;
UidMap::UidMap() : mBytesUsed(0) {}
@@ -312,7 +316,7 @@ size_t UidMap::getBytesUsed() const {
}
void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key,
- ProtoOutputStream* proto) {
+ std::set<string> *str_set, ProtoOutputStream* proto) {
lock_guard<mutex> lock(mMutex); // Lock for updates
for (const ChangeRecord& record : mChanges) {
@@ -322,7 +326,14 @@ void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key,
proto->write(FIELD_TYPE_BOOL | FIELD_ID_CHANGE_DELETION, (bool)record.deletion);
proto->write(FIELD_TYPE_INT64 | FIELD_ID_CHANGE_TIMESTAMP,
(long long)record.timestampNs);
- proto->write(FIELD_TYPE_STRING | FIELD_ID_CHANGE_PACKAGE, record.package);
+ if (str_set != nullptr) {
+ str_set->insert(record.package);
+ proto->write(FIELD_TYPE_UINT64 | FIELD_ID_CHANGE_PACKAGE_HASH,
+ (long long)Hash64(record.package));
+ } else {
+ proto->write(FIELD_TYPE_STRING | FIELD_ID_CHANGE_PACKAGE, record.package);
+ }
+
proto->write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_UID, (int)record.uid);
proto->write(FIELD_TYPE_INT64 | FIELD_ID_CHANGE_NEW_VERSION, (long long)record.version);
proto->write(FIELD_TYPE_INT64 | FIELD_ID_CHANGE_PREV_VERSION,
@@ -338,7 +349,15 @@ void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key,
for (const auto& kv : mMap) {
uint64_t token = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
FIELD_ID_SNAPSHOT_PACKAGE_INFO);
- proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME, kv.first.second);
+
+ if (str_set != nullptr) {
+ str_set->insert(kv.first.second);
+ proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_NAME_HASH,
+ (long long)Hash64(kv.first.second));
+ } else {
+ proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME, kv.first.second);
+ }
+
proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION,
(long long)kv.second.versionCode);
proto->write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID, kv.first.first);
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 755b7079ec34..5e42cd18de32 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -128,7 +128,7 @@ public:
// If every config key has received a change or snapshot record, then this
// record is deleted.
void appendUidMap(const int64_t& timestamp, const ConfigKey& key,
- util::ProtoOutputStream* proto);
+ std::set<string> *str_set, util::ProtoOutputStream* proto);
// Forces the output to be cleared. We still generate a snapshot based on the current state.
// This results in extra data uploaded but helps us reconstruct the uid mapping on the server
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 447e4b70fb71..923686433d12 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -33,6 +33,7 @@ message DimensionsValue {
bool value_bool = 5;
float value_float = 6;
DimensionsValueTuple value_tuple = 7;
+ uint64 value_str_hash = 8;
}
}
@@ -54,6 +55,12 @@ message CountBucketInfo {
optional int64 end_bucket_elapsed_nanos = 2;
optional int64 count = 3;
+
+ optional int64 bucket_num = 4;
+
+ optional int64 start_bucket_elapsed_millis = 5;
+
+ optional int64 end_bucket_elapsed_millis = 6;
}
message CountMetricData {
@@ -62,6 +69,10 @@ message CountMetricData {
optional DimensionsValue dimensions_in_condition = 2;
repeated CountBucketInfo bucket_info = 3;
+
+ repeated DimensionsValue dimension_leaf_values_in_what = 4;
+
+ repeated DimensionsValue dimension_leaf_values_in_condition = 5;
}
message DurationBucketInfo {
@@ -70,6 +81,12 @@ message DurationBucketInfo {
optional int64 end_bucket_elapsed_nanos = 2;
optional int64 duration_nanos = 3;
+
+ optional int64 bucket_num = 4;
+
+ optional int64 start_bucket_elapsed_millis = 5;
+
+ optional int64 end_bucket_elapsed_millis = 6;
}
message DurationMetricData {
@@ -78,6 +95,10 @@ message DurationMetricData {
optional DimensionsValue dimensions_in_condition = 2;
repeated DurationBucketInfo bucket_info = 3;
+
+ repeated DimensionsValue dimension_leaf_values_in_what = 4;
+
+ repeated DimensionsValue dimension_leaf_values_in_condition = 5;
}
message ValueBucketInfo {
@@ -86,6 +107,12 @@ message ValueBucketInfo {
optional int64 end_bucket_elapsed_nanos = 2;
optional int64 value = 3;
+
+ optional int64 bucket_num = 4;
+
+ optional int64 start_bucket_elapsed_millis = 5;
+
+ optional int64 end_bucket_elapsed_millis = 6;
}
message ValueMetricData {
@@ -94,6 +121,10 @@ message ValueMetricData {
optional DimensionsValue dimensions_in_condition = 2;
repeated ValueBucketInfo bucket_info = 3;
+
+ repeated DimensionsValue dimension_leaf_values_in_what = 4;
+
+ repeated DimensionsValue dimension_leaf_values_in_condition = 5;
}
message GaugeBucketInfo {
@@ -106,6 +137,12 @@ message GaugeBucketInfo {
repeated int64 elapsed_timestamp_nanos = 4;
repeated int64 wall_clock_timestamp_nanos = 5;
+
+ optional int64 bucket_num = 6;
+
+ optional int64 start_bucket_elapsed_millis = 7;
+
+ optional int64 end_bucket_elapsed_millis = 8;
}
message GaugeMetricData {
@@ -114,6 +151,10 @@ message GaugeMetricData {
optional DimensionsValue dimensions_in_condition = 2;
repeated GaugeBucketInfo bucket_info = 3;
+
+ repeated DimensionsValue dimension_leaf_values_in_what = 4;
+
+ repeated DimensionsValue dimension_leaf_values_in_condition = 5;
}
message StatsLogReport {
@@ -122,8 +163,10 @@ message StatsLogReport {
// Fields 2 and 3 are reserved.
message SkippedBuckets {
- optional int64 start_elapsed_nanos = 1;
- optional int64 end_elapsed_nanos = 2;
+ optional int64 start_bucket_elapsed_nanos = 1;
+ optional int64 end_bucket_elapsed_nanos = 2;
+ optional int64 start_bucket_elapsed_millis = 3;
+ optional int64 end_bucket_elapsed_millis = 4;
}
message EventMetricDataWrapper {
@@ -152,6 +195,14 @@ message StatsLogReport {
ValueMetricDataWrapper value_metrics = 7;
GaugeMetricDataWrapper gauge_metrics = 8;
}
+
+ optional int64 time_base_elapsed_nano_seconds = 9;
+
+ optional int64 bucket_size_nano_seconds = 10;
+
+ optional DimensionsValue dimensions_path_in_what = 11;
+
+ optional DimensionsValue dimensions_path_in_condition = 12;
}
message UidMapping {
@@ -164,6 +215,8 @@ message UidMapping {
optional int32 uid = 3;
optional bool deleted = 4;
+
+ optional uint64 name_hash = 5;
}
optional int64 elapsed_timestamp_nanos = 1;
@@ -180,6 +233,7 @@ message UidMapping {
optional int64 new_version = 5;
optional int64 prev_version = 6;
+ optional uint64 app_hash = 7;
}
repeated Change changes = 2;
}
@@ -197,6 +251,12 @@ message ConfigMetricsReport {
optional int64 current_report_wall_clock_nanos = 6;
+ message Annotation {
+ optional int64 field_int64 = 1;
+ optional int32 field_int32 = 2;
+ }
+ repeated Annotation annotation = 7;
+
enum DumpReportReason {
DEVICE_SHUTDOWN = 1;
CONFIG_UPDATED = 2;
@@ -208,11 +268,7 @@ message ConfigMetricsReport {
}
optional DumpReportReason dump_report_reason = 8;
- message Annotation {
- optional int64 field_int64 = 1;
- optional int32 field_int32 = 2;
- }
- repeated Annotation annotation = 7;
+ repeated string strings = 9;
}
message ConfigMetricsReportList {
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index efd810f01140..a0ab3e46e719 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "hash.h"
#include "stats_log_util.h"
#include <logd/LogEvent.h>
@@ -29,6 +30,8 @@ using android::util::FIELD_TYPE_BOOL;
using android::util::FIELD_TYPE_FLOAT;
using android::util::FIELD_TYPE_INT32;
using android::util::FIELD_TYPE_INT64;
+using android::util::FIELD_TYPE_UINT64;
+using android::util::FIELD_TYPE_FIXED64;
using android::util::FIELD_TYPE_MESSAGE;
using android::util::FIELD_TYPE_STRING;
using android::util::ProtoOutputStream;
@@ -45,6 +48,7 @@ const int DIMENSIONS_VALUE_VALUE_LONG = 4;
// 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_VALUE_STR_HASH = 8;
const int DIMENSIONS_VALUE_TUPLE_VALUE = 1;
@@ -54,10 +58,12 @@ const int FIELD_ID_PULL_ATOM_ID = 1;
const int FIELD_ID_TOTAL_PULL = 2;
const int FIELD_ID_TOTAL_PULL_FROM_CACHE = 3;
const int FIELD_ID_MIN_PULL_INTERVAL_SEC = 4;
+
namespace {
void writeDimensionToProtoHelper(const std::vector<FieldValue>& dims, size_t* index, int depth,
- int prefix, ProtoOutputStream* protoOutput) {
+ int prefix, std::set<string> *str_set,
+ ProtoOutputStream* protoOutput) {
size_t count = dims.size();
while (*index < count) {
const auto& dim = dims[*index];
@@ -87,8 +93,15 @@ void writeDimensionToProtoHelper(const std::vector<FieldValue>& dims, size_t* in
dim.mValue.float_value);
break;
case STRING:
- protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
- dim.mValue.str_value);
+ if (str_set == nullptr) {
+ protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
+ dim.mValue.str_value);
+ } else {
+ str_set->insert(dim.mValue.str_value);
+ protoOutput->write(
+ FIELD_TYPE_UINT64 | DIMENSIONS_VALUE_VALUE_STR_HASH,
+ (long long)Hash64(dim.mValue.str_value));
+ }
break;
default:
break;
@@ -105,7 +118,107 @@ void writeDimensionToProtoHelper(const std::vector<FieldValue>& dims, size_t* in
uint64_t tupleToken =
protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
writeDimensionToProtoHelper(dims, index, valueDepth, dim.mField.getPrefix(valueDepth),
- protoOutput);
+ str_set, protoOutput);
+ protoOutput->end(tupleToken);
+ protoOutput->end(dimensionToken);
+ } else {
+ // Done with the prev sub tree
+ return;
+ }
+ }
+}
+
+void writeDimensionLeafToProtoHelper(const std::vector<FieldValue>& dims,
+ const int dimensionLeafField,
+ size_t* index, int depth,
+ int prefix, std::set<string> *str_set,
+ ProtoOutputStream* protoOutput) {
+ size_t count = dims.size();
+ while (*index < count) {
+ const auto& dim = dims[*index];
+ const int valueDepth = dim.mField.getDepth();
+ const int valuePrefix = dim.mField.getPrefix(depth);
+ if (valueDepth > 2) {
+ ALOGE("Depth > 2 not supported");
+ return;
+ }
+
+ if (depth == valueDepth && valuePrefix == prefix) {
+ uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+ dimensionLeafField);
+ switch (dim.mValue.getType()) {
+ case INT:
+ protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_VALUE_INT,
+ dim.mValue.int_value);
+ break;
+ case LONG:
+ protoOutput->write(FIELD_TYPE_INT64 | DIMENSIONS_VALUE_VALUE_LONG,
+ (long long)dim.mValue.long_value);
+ break;
+ case FLOAT:
+ protoOutput->write(FIELD_TYPE_FLOAT | DIMENSIONS_VALUE_VALUE_FLOAT,
+ dim.mValue.float_value);
+ break;
+ case STRING:
+ if (str_set == nullptr) {
+ protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
+ dim.mValue.str_value);
+ } else {
+ str_set->insert(dim.mValue.str_value);
+ protoOutput->write(
+ FIELD_TYPE_UINT64 | DIMENSIONS_VALUE_VALUE_STR_HASH,
+ (long long)Hash64(dim.mValue.str_value));
+ }
+ break;
+ default:
+ break;
+ }
+ if (token != 0) {
+ protoOutput->end(token);
+ }
+ (*index)++;
+ } else if (valueDepth > depth && valuePrefix == prefix) {
+ writeDimensionLeafToProtoHelper(dims, dimensionLeafField,
+ index, valueDepth, dim.mField.getPrefix(valueDepth),
+ str_set, protoOutput);
+ } else {
+ // Done with the prev sub tree
+ return;
+ }
+ }
+}
+
+void writeDimensionPathToProtoHelper(const std::vector<Matcher>& fieldMatchers,
+ size_t* index, int depth, int prefix,
+ ProtoOutputStream* protoOutput) {
+ size_t count = fieldMatchers.size();
+ while (*index < count) {
+ const Field& field = fieldMatchers[*index].mMatcher;
+ const int valueDepth = field.getDepth();
+ const int valuePrefix = field.getPrefix(depth);
+ const int fieldNum = field.getPosAtDepth(depth);
+ if (valueDepth > 2) {
+ ALOGE("Depth > 2 not supported");
+ return;
+ }
+
+ if (depth == valueDepth && valuePrefix == prefix) {
+ uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+ DIMENSIONS_VALUE_TUPLE_VALUE);
+ protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
+ if (token != 0) {
+ protoOutput->end(token);
+ }
+ (*index)++;
+ } else if (valueDepth > depth && valuePrefix == prefix) {
+ // Writing the sub tree
+ uint64_t dimensionToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | DIMENSIONS_VALUE_TUPLE_VALUE);
+ protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
+ uint64_t tupleToken =
+ protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
+ writeDimensionPathToProtoHelper(fieldMatchers, index, valueDepth,
+ field.getPrefix(valueDepth), protoOutput);
protoOutput->end(tupleToken);
protoOutput->end(dimensionToken);
} else {
@@ -117,7 +230,8 @@ void writeDimensionToProtoHelper(const std::vector<FieldValue>& dims, size_t* in
} // namespace
-void writeDimensionToProto(const HashableDimensionKey& dimension, ProtoOutputStream* protoOutput) {
+void writeDimensionToProto(const HashableDimensionKey& dimension, std::set<string> *str_set,
+ ProtoOutputStream* protoOutput) {
if (dimension.getValues().size() == 0) {
return;
}
@@ -125,7 +239,32 @@ void writeDimensionToProto(const HashableDimensionKey& dimension, ProtoOutputStr
dimension.getValues()[0].mField.getTag());
uint64_t topToken = protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
size_t index = 0;
- writeDimensionToProtoHelper(dimension.getValues(), &index, 0, 0, protoOutput);
+ writeDimensionToProtoHelper(dimension.getValues(), &index, 0, 0, str_set, protoOutput);
+ protoOutput->end(topToken);
+}
+
+void writeDimensionLeafNodesToProto(const HashableDimensionKey& dimension,
+ const int dimensionLeafFieldId,
+ std::set<string> *str_set,
+ ProtoOutputStream* protoOutput) {
+ if (dimension.getValues().size() == 0) {
+ return;
+ }
+ size_t index = 0;
+ writeDimensionLeafToProtoHelper(dimension.getValues(), dimensionLeafFieldId,
+ &index, 0, 0, str_set, protoOutput);
+}
+
+void writeDimensionPathToProto(const std::vector<Matcher>& fieldMatchers,
+ ProtoOutputStream* protoOutput) {
+ if (fieldMatchers.size() == 0) {
+ return;
+ }
+ protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD,
+ fieldMatchers[0].mMatcher.getTag());
+ uint64_t topToken = protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
+ size_t index = 0;
+ writeDimensionPathToProtoHelper(fieldMatchers, &index, 0, 0, protoOutput);
protoOutput->end(topToken);
}
@@ -297,6 +436,14 @@ int64_t truncateTimestampNsToFiveMinutes(int64_t timestampNs) {
return timestampNs / NS_PER_SEC / (5 * 60) * NS_PER_SEC * (5 * 60);
}
+int64_t NanoToMillis(const int64_t nano) {
+ return nano / 1000000;
+}
+
+int64_t MillisToNano(const int64_t millis) {
+ return millis * 1000000;
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h
index 97220500073d..b8f6850ddc29 100644
--- a/cmds/statsd/src/stats_log_util.h
+++ b/cmds/statsd/src/stats_log_util.h
@@ -28,9 +28,17 @@ namespace statsd {
void writeFieldValueTreeToStream(int tagId, const std::vector<FieldValue>& values,
util::ProtoOutputStream* protoOutput);
-void writeDimensionToProto(const HashableDimensionKey& dimension,
+void writeDimensionToProto(const HashableDimensionKey& dimension, std::set<string> *str_set,
util::ProtoOutputStream* protoOutput);
+void writeDimensionLeafNodesToProto(const HashableDimensionKey& dimension,
+ const int dimensionLeafFieldId,
+ std::set<string> *str_set,
+ util::ProtoOutputStream* protoOutput);
+
+void writeDimensionPathToProto(const std::vector<Matcher>& fieldMatchers,
+ 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);
@@ -56,6 +64,10 @@ int64_t getWallClockMillis();
// Gets the wall clock timestamp in seconds.
int64_t getWallClockSec();
+int64_t NanoToMillis(const int64_t nano);
+
+int64_t MillisToNano(const int64_t millis);
+
// Helper function to write PulledAtomStats to ProtoOutputStream
void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>& pair,
util::ProtoOutputStream* protoOutput);
diff --git a/cmds/statsd/tests/FieldValue_test.cpp b/cmds/statsd/tests/FieldValue_test.cpp
index 5a6aba624d7d..c253bc19d641 100644
--- a/cmds/statsd/tests/FieldValue_test.cpp
+++ b/cmds/statsd/tests/FieldValue_test.cpp
@@ -226,6 +226,68 @@ TEST(AtomMatcherTest, TestMetric2ConditionLink) {
EXPECT_EQ((int32_t)27, link.conditionFields[0].mMatcher.getTag());
}
+TEST(AtomMatcherTest, TestWriteDimensionPath) {
+ for (auto position : {Position::ANY, Position::ALL, Position::FIRST, Position::LAST}) {
+ FieldMatcher matcher1;
+ matcher1.set_field(10);
+ FieldMatcher* child = matcher1.add_child();
+ child->set_field(2);
+ child->set_position(position);
+ child->add_child()->set_field(1);
+ child->add_child()->set_field(3);
+
+ child = matcher1.add_child();
+ child->set_field(4);
+
+ child = matcher1.add_child();
+ child->set_field(6);
+ child->add_child()->set_field(2);
+
+ vector<Matcher> matchers;
+ translateFieldMatcher(matcher1, &matchers);
+
+ android::util::ProtoOutputStream protoOut;
+ writeDimensionPathToProto(matchers, &protoOut);
+
+ vector<uint8_t> outData;
+ outData.resize(protoOut.size());
+ size_t pos = 0;
+ auto iter = protoOut.data();
+ while (iter.readBuffer() != NULL) {
+ size_t toRead = iter.currentToRead();
+ std::memcpy(&(outData[pos]), iter.readBuffer(), toRead);
+ pos += toRead;
+ iter.rp()->move(toRead);
+ }
+
+ DimensionsValue result;
+ EXPECT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
+
+ EXPECT_EQ(10, result.field());
+ EXPECT_EQ(DimensionsValue::ValueCase::kValueTuple, result.value_case());
+ EXPECT_EQ(3, result.value_tuple().dimensions_value_size());
+
+ const auto& dim1 = result.value_tuple().dimensions_value(0);
+ EXPECT_EQ(2, dim1.field());
+ EXPECT_EQ(2, dim1.value_tuple().dimensions_value_size());
+
+ const auto& dim11 = dim1.value_tuple().dimensions_value(0);
+ EXPECT_EQ(1, dim11.field());
+
+ const auto& dim12 = dim1.value_tuple().dimensions_value(1);
+ EXPECT_EQ(3, dim12.field());
+
+ const auto& dim2 = result.value_tuple().dimensions_value(1);
+ EXPECT_EQ(4, dim2.field());
+
+ const auto& dim3 = result.value_tuple().dimensions_value(2);
+ EXPECT_EQ(6, dim3.field());
+ EXPECT_EQ(1, dim3.value_tuple().dimensions_value_size());
+ const auto& dim31 = dim3.value_tuple().dimensions_value(0);
+ EXPECT_EQ(2, dim31.field());
+ }
+}
+
TEST(AtomMatcherTest, TestSubscriberDimensionWrite) {
HashableDimensionKey dim;
@@ -275,7 +337,7 @@ TEST(AtomMatcherTest, TestWriteDimensionToProto) {
dim.addValue(FieldValue(field4, value4));
android::util::ProtoOutputStream protoOut;
- writeDimensionToProto(dim, &protoOut);
+ writeDimensionToProto(dim, nullptr /* include strings */, &protoOut);
vector<uint8_t> outData;
outData.resize(protoOut.size());
@@ -315,6 +377,62 @@ TEST(AtomMatcherTest, TestWriteDimensionToProto) {
EXPECT_EQ(99999, dim2.value_int());
}
+TEST(AtomMatcherTest, TestWriteDimensionLeafNodesToProto) {
+ HashableDimensionKey dim;
+ int pos1[] = {1, 1, 1};
+ int pos2[] = {1, 1, 2};
+ int pos3[] = {1, 1, 3};
+ int pos4[] = {2, 0, 0};
+ Field field1(10, pos1, 2);
+ Field field2(10, pos2, 2);
+ Field field3(10, pos3, 2);
+ Field field4(10, pos4, 0);
+
+ Value value1((int32_t)10025);
+ Value value2("tag");
+ Value value3((int32_t)987654);
+ Value value4((int64_t)99999);
+
+ dim.addValue(FieldValue(field1, value1));
+ dim.addValue(FieldValue(field2, value2));
+ dim.addValue(FieldValue(field3, value3));
+ dim.addValue(FieldValue(field4, value4));
+
+ android::util::ProtoOutputStream protoOut;
+ writeDimensionLeafNodesToProto(dim, 1, nullptr /* include strings */, &protoOut);
+
+ vector<uint8_t> outData;
+ outData.resize(protoOut.size());
+ size_t pos = 0;
+ auto iter = protoOut.data();
+ while (iter.readBuffer() != NULL) {
+ size_t toRead = iter.currentToRead();
+ std::memcpy(&(outData[pos]), iter.readBuffer(), toRead);
+ pos += toRead;
+ iter.rp()->move(toRead);
+ }
+
+ DimensionsValueTuple result;
+ EXPECT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
+ EXPECT_EQ(4, result.dimensions_value_size());
+
+ const auto& dim1 = result.dimensions_value(0);
+ EXPECT_EQ(DimensionsValue::ValueCase::kValueInt, dim1.value_case());
+ EXPECT_EQ(10025, dim1.value_int());
+
+ const auto& dim2 = result.dimensions_value(1);
+ EXPECT_EQ(DimensionsValue::ValueCase::kValueStr, dim2.value_case());
+ EXPECT_EQ("tag", dim2.value_str());
+
+ const auto& dim3 = result.dimensions_value(2);
+ EXPECT_EQ(DimensionsValue::ValueCase::kValueInt, dim3.value_case());
+ EXPECT_EQ(987654, dim3.value_int());
+
+ const auto& dim4 = result.dimensions_value(3);
+ EXPECT_EQ(DimensionsValue::ValueCase::kValueLong, dim4.value_case());
+ EXPECT_EQ(99999, dim4.value_long());
+}
+
TEST(AtomMatcherTest, TestWriteAtomToProto) {
AttributionNodeInternal attribution_node1;
attribution_node1.set_uid(1111);
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index 004b2358fc1b..9fdf7a33a7d0 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -139,7 +139,7 @@ TEST(StatsLogProcessorTest, TestUidMapHasSnapshot) {
// Expect to get no metrics, but snapshot specified above in uidmap.
vector<uint8_t> bytes;
- p.onDumpReport(key, 1, false, ADB_DUMP, &bytes);
+ p.onDumpReport(key, 1, false, true, ADB_DUMP, &bytes);
ConfigMetricsReportList output;
output.ParseFromArray(bytes.data(), bytes.size());
@@ -167,7 +167,7 @@ TEST(StatsLogProcessorTest, TestReportIncludesSubConfig) {
// Expect to get no metrics, but snapshot specified above in uidmap.
vector<uint8_t> bytes;
- p.onDumpReport(key, 1, false, ADB_DUMP, &bytes);
+ p.onDumpReport(key, 1, false, true, ADB_DUMP, &bytes);
ConfigMetricsReportList output;
output.ParseFromArray(bytes.data(), bytes.size());
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index 2fab9750314c..dde50c2597da 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -17,6 +17,7 @@
#include "config/ConfigKey.h"
#include "guardrail/StatsdStats.h"
#include "logd/LogEvent.h"
+#include "hash.h"
#include "statslog.h"
#include "statsd_test_util.h"
@@ -192,7 +193,7 @@ TEST(UidMapTest, TestOutputIncludesAtLeastOneSnapshot) {
m.mLastUpdatePerConfigKey[config1] = 2;
ProtoOutputStream proto;
- m.appendUidMap(3, config1, &proto);
+ m.appendUidMap(3, config1, nullptr, &proto);
// Check there's still a uidmap attached this one.
UidMapping results;
@@ -215,7 +216,7 @@ TEST(UidMapTest, TestRemovedAppRetained) {
m.removeApp(2, String16(kApp2.c_str()), 1000);
ProtoOutputStream proto;
- m.appendUidMap(3, config1, &proto);
+ m.appendUidMap(3, config1, nullptr, &proto);
// Snapshot should still contain this item as deleted.
UidMapping results;
@@ -243,7 +244,7 @@ TEST(UidMapTest, TestRemovedAppOverGuardrail) {
// First, verify that we have the expected number of items.
UidMapping results;
ProtoOutputStream proto;
- m.appendUidMap(3, config1, &proto);
+ m.appendUidMap(3, config1, nullptr, &proto);
protoOutputStreamToUidMapping(&proto, &results);
EXPECT_EQ(maxDeletedApps + 10, results.snapshots(0).package_info_size());
@@ -254,7 +255,7 @@ TEST(UidMapTest, TestRemovedAppOverGuardrail) {
}
proto.clear();
- m.appendUidMap(5, config1, &proto);
+ m.appendUidMap(5, config1, nullptr, &proto);
// Snapshot drops the first nine items.
protoOutputStreamToUidMapping(&proto, &results);
EXPECT_EQ(maxDeletedApps, results.snapshots(0).package_info_size());
@@ -280,14 +281,14 @@ TEST(UidMapTest, TestClearingOutput) {
m.updateMap(1, uids, versions, apps);
ProtoOutputStream proto;
- m.appendUidMap(2, config1, &proto);
+ m.appendUidMap(2, config1, nullptr, &proto);
UidMapping results;
protoOutputStreamToUidMapping(&proto, &results);
EXPECT_EQ(1, results.snapshots_size());
// We have to keep at least one snapshot in memory at all times.
proto.clear();
- m.appendUidMap(2, config1, &proto);
+ m.appendUidMap(2, config1, nullptr, &proto);
protoOutputStreamToUidMapping(&proto, &results);
EXPECT_EQ(1, results.snapshots_size());
@@ -296,7 +297,7 @@ TEST(UidMapTest, TestClearingOutput) {
m.updateApp(5, String16(kApp1.c_str()), 1000, 40);
EXPECT_EQ(1U, m.mChanges.size());
proto.clear();
- m.appendUidMap(6, config1, &proto);
+ m.appendUidMap(6, config1, nullptr, &proto);
protoOutputStreamToUidMapping(&proto, &results);
EXPECT_EQ(1, results.snapshots_size());
EXPECT_EQ(1, results.changes_size());
@@ -308,14 +309,14 @@ TEST(UidMapTest, TestClearingOutput) {
// We still can't remove anything.
proto.clear();
- m.appendUidMap(8, config1, &proto);
+ m.appendUidMap(8, config1, nullptr, &proto);
protoOutputStreamToUidMapping(&proto, &results);
EXPECT_EQ(1, results.snapshots_size());
EXPECT_EQ(1, results.changes_size());
EXPECT_EQ(2U, m.mChanges.size());
proto.clear();
- m.appendUidMap(9, config2, &proto);
+ m.appendUidMap(9, config2, nullptr, &proto);
protoOutputStreamToUidMapping(&proto, &results);
EXPECT_EQ(1, results.snapshots_size());
EXPECT_EQ(2, results.changes_size());
@@ -342,10 +343,10 @@ TEST(UidMapTest, TestMemoryComputed) {
ProtoOutputStream proto;
vector<uint8_t> bytes;
- m.appendUidMap(2, config1, &proto);
+ m.appendUidMap(2, config1, nullptr, &proto);
size_t prevBytes = m.mBytesUsed;
- m.appendUidMap(4, config1, &proto);
+ m.appendUidMap(4, config1, nullptr, &proto);
EXPECT_TRUE(m.mBytesUsed < prevBytes);
}
@@ -376,6 +377,7 @@ TEST(UidMapTest, TestMemoryGuardrail) {
m.updateApp(5, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 4);
EXPECT_EQ(1U, m.mChanges.size());
}
+
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index 3b24341865d1..5c47af797eea 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -144,10 +144,13 @@ TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid) {
}
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
@@ -287,10 +290,13 @@ TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain) {
}
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
index 934b95101fed..8a74f2de259e 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
@@ -172,10 +172,13 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondi
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- ADB_DUMP, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1,
+ false, true, ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
@@ -489,10 +492,13 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_AND_CombinationConditi
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
@@ -733,10 +739,13 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_AND_Combination
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
index 9f20754fafff..d4fe712329cf 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
@@ -130,10 +130,13 @@ TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCon
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
@@ -343,10 +346,13 @@ TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondi
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
@@ -524,10 +530,13 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_OR_CombinationCondit
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
@@ -723,10 +732,13 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_OR_CombinationConditio
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
index 3f193ac519f7..97089ca74c42 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
@@ -142,10 +142,13 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_SimpleCondition) {
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
@@ -434,10 +437,13 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_SimpleCondition) {
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
@@ -652,10 +658,13 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_SimpleCondition
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index f4ad0ce75602..6a69100b83b0 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -122,10 +122,13 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(1, reports.reports_size());
EXPECT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
@@ -241,10 +244,13 @@ TEST(GaugeMetricE2eTest, TestAllConditionChangesSamplePulledEvents) {
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(1, reports.reports_size());
EXPECT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
@@ -342,10 +348,13 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) {
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(1, reports.reports_size());
EXPECT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
index 98372ff795c0..f1052f69e6f2 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
@@ -149,10 +149,13 @@ TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) {
}
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(1, reports.reports_size());
EXPECT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index 802078719be2..eca35c59997e 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -200,10 +200,13 @@ TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1) {
}
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
@@ -316,10 +319,13 @@ TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2) {
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index d646f73f9fa2..545fa015b3ec 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -46,7 +46,7 @@ ConfigMetricsReport GetReports(sp<StatsLogProcessor> processor, int64_t timestam
IPCThreadState* ipc = IPCThreadState::self();
ConfigKey configKey(ipc->getCallingUid(), kConfigKey);
processor->onDumpReport(configKey, timestamp, include_current /* include_current_bucket*/,
- ADB_DUMP, &output);
+ true/* include strings*/, ADB_DUMP, &output);
ConfigMetricsReportList reports;
reports.ParseFromArray(output.data(), output.size());
EXPECT_EQ(1, reports.reports_size());
@@ -153,7 +153,12 @@ TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
ConfigMetricsReport report = GetReports(service.mProcessor, start + 4);
+ backfillStartEndTimestamp(&report);
EXPECT_EQ(1, report.metrics_size());
+ EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
+ has_start_bucket_elapsed_nanos());
+ EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
+ has_end_bucket_elapsed_nanos());
EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
}
@@ -171,7 +176,12 @@ TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
ConfigMetricsReport report = GetReports(service.mProcessor, start + 4);
+ backfillStartEndTimestamp(&report);
EXPECT_EQ(1, report.metrics_size());
+ EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
+ has_start_bucket_elapsed_nanos());
+ EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
+ has_end_bucket_elapsed_nanos());
EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
}
@@ -206,10 +216,13 @@ TEST(PartialBucketE2eTest, TestValueMetricWithMinPartialBucket) {
ConfigMetricsReport report =
GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC, true);
+ backfillStartEndTimestamp(&report);
EXPECT_EQ(1, report.metrics_size());
EXPECT_EQ(1, report.metrics(0).value_metrics().skipped_size());
+ EXPECT_TRUE(report.metrics(0).value_metrics().skipped(0).has_start_bucket_elapsed_nanos());
// Can't test the start time since it will be based on the actual time when the pulling occurs.
- EXPECT_EQ(endSkipped, report.metrics(0).value_metrics().skipped(0).end_elapsed_nanos());
+ EXPECT_EQ(MillisToNano(NanoToMillis(endSkipped)),
+ report.metrics(0).value_metrics().skipped(0).end_bucket_elapsed_nanos());
}
TEST(PartialBucketE2eTest, TestGaugeMetricWithoutMinPartialBucket) {
@@ -243,10 +256,13 @@ TEST(PartialBucketE2eTest, TestGaugeMetricWithMinPartialBucket) {
ConfigMetricsReport report =
GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC, true);
+ backfillStartEndTimestamp(&report);
EXPECT_EQ(1, report.metrics_size());
EXPECT_EQ(1, report.metrics(0).gauge_metrics().skipped_size());
// Can't test the start time since it will be based on the actual time when the pulling occurs.
- EXPECT_EQ(endSkipped, report.metrics(0).gauge_metrics().skipped(0).end_elapsed_nanos());
+ EXPECT_TRUE(report.metrics(0).gauge_metrics().skipped(0).has_start_bucket_elapsed_nanos());
+ EXPECT_EQ(MillisToNano(NanoToMillis(endSkipped)),
+ report.metrics(0).gauge_metrics().skipped(0).end_bucket_elapsed_nanos());
}
#else
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
index a01e91f5aad2..98a312f7ded6 100644
--- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -117,10 +117,13 @@ TEST(ValueMetricE2eTest, TestPulledEvents) {
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(1, reports.reports_size());
EXPECT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::ValueMetricDataWrapper valueMetrics;
@@ -221,10 +224,13 @@ TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm) {
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(1, reports.reports_size());
EXPECT_EQ(1, reports.reports(0).metrics_size());
StatsLogReport::ValueMetricDataWrapper valueMetrics;
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index 974e4423c82a..6d1317cb5dee 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -127,10 +127,13 @@ TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1)
FeedEvents(config, processor);
vector<uint8_t> buffer;
ConfigMetricsReportList reports;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
@@ -161,11 +164,13 @@ TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2)
FeedEvents(config, processor);
vector<uint8_t> buffer;
ConfigMetricsReportList reports;
-
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
@@ -210,10 +215,13 @@ TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration3)
processor->OnLogEvent(event.get());
}
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
@@ -240,11 +248,14 @@ TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration1)
FeedEvents(config, processor);
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(reports.reports_size(), 1);
@@ -266,10 +277,13 @@ TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration2)
FeedEvents(config, processor);
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
@@ -309,10 +323,13 @@ TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration3)
processor->OnLogEvent(event.get());
}
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 12649093059b..590399312b88 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -645,6 +645,183 @@ bool LessThan(const DimensionsPair& s1, const DimensionsPair& s2) {
return LessThan(s1.dimInCondition, s2.dimInCondition);
}
+void backfillStringInDimension(const std::map<uint64_t, string>& str_map,
+ DimensionsValue* dimension) {
+ if (dimension->has_value_str_hash()) {
+ auto it = str_map.find((uint64_t)(dimension->value_str_hash()));
+ if (it != str_map.end()) {
+ dimension->clear_value_str_hash();
+ dimension->set_value_str(it->second);
+ } else {
+ ALOGE("Can not find the string hash: %llu",
+ (unsigned long long)dimension->value_str_hash());
+ }
+ } else if (dimension->has_value_tuple()) {
+ auto value_tuple = dimension->mutable_value_tuple();
+ for (int i = 0; i < value_tuple->dimensions_value_size(); ++i) {
+ backfillStringInDimension(str_map, value_tuple->mutable_dimensions_value(i));
+ }
+ }
+}
+
+void backfillStringInReport(ConfigMetricsReport *config_report) {
+ std::map<uint64_t, string> str_map;
+ for (const auto& str : config_report->strings()) {
+ uint64_t hash = Hash64(str);
+ if (str_map.find(hash) != str_map.end()) {
+ ALOGE("String hash conflicts: %s %s", str.c_str(), str_map[hash].c_str());
+ }
+ str_map[hash] = str;
+ }
+ for (int i = 0; i < config_report->metrics_size(); ++i) {
+ auto metric_report = config_report->mutable_metrics(i);
+ if (metric_report->has_count_metrics()) {
+ backfillStringInDimension(str_map, metric_report->mutable_count_metrics());
+ } else if (metric_report->has_duration_metrics()) {
+ backfillStringInDimension(str_map, metric_report->mutable_duration_metrics());
+ } else if (metric_report->has_gauge_metrics()) {
+ backfillStringInDimension(str_map, metric_report->mutable_gauge_metrics());
+ } else if (metric_report->has_value_metrics()) {
+ backfillStringInDimension(str_map, metric_report->mutable_value_metrics());
+ }
+ }
+ // Backfill the package names.
+ for (int i = 0 ; i < config_report->uid_map().snapshots_size(); ++i) {
+ auto snapshot = config_report->mutable_uid_map()->mutable_snapshots(i);
+ for (int j = 0 ; j < snapshot->package_info_size(); ++j) {
+ auto package_info = snapshot->mutable_package_info(j);
+ if (package_info->has_name_hash()) {
+ auto it = str_map.find((uint64_t)(package_info->name_hash()));
+ if (it != str_map.end()) {
+ package_info->clear_name_hash();
+ package_info->set_name(it->second);
+ } else {
+ ALOGE("Can not find the string package name hash: %llu",
+ (unsigned long long)package_info->name_hash());
+ }
+
+ }
+ }
+ }
+ // Backfill the app name in app changes.
+ for (int i = 0 ; i < config_report->uid_map().changes_size(); ++i) {
+ auto change = config_report->mutable_uid_map()->mutable_changes(i);
+ if (change->has_app_hash()) {
+ auto it = str_map.find((uint64_t)(change->app_hash()));
+ if (it != str_map.end()) {
+ change->clear_app_hash();
+ change->set_app(it->second);
+ } else {
+ ALOGE("Can not find the string change app name hash: %llu",
+ (unsigned long long)change->app_hash());
+ }
+ }
+ }
+}
+
+void backfillStringInReport(ConfigMetricsReportList *config_report_list) {
+ for (int i = 0; i < config_report_list->reports_size(); ++i) {
+ backfillStringInReport(config_report_list->mutable_reports(i));
+ }
+}
+
+bool backfillDimensionPath(const DimensionsValue& path,
+ const google::protobuf::RepeatedPtrField<DimensionsValue>& leafValues,
+ int* leafIndex,
+ DimensionsValue* dimension) {
+ dimension->set_field(path.field());
+ if (path.has_value_tuple()) {
+ for (int i = 0; i < path.value_tuple().dimensions_value_size(); ++i) {
+ if (!backfillDimensionPath(
+ path.value_tuple().dimensions_value(i), leafValues, leafIndex,
+ dimension->mutable_value_tuple()->add_dimensions_value())) {
+ return false;
+ }
+ }
+ } else {
+ if (*leafIndex < 0 || *leafIndex >= leafValues.size()) {
+ return false;
+ }
+ dimension->MergeFrom(leafValues.Get(*leafIndex));
+ (*leafIndex)++;
+ }
+ return true;
+}
+
+bool backfillDimensionPath(const DimensionsValue& path,
+ const google::protobuf::RepeatedPtrField<DimensionsValue>& leafValues,
+ DimensionsValue* dimension) {
+ int leafIndex = 0;
+ return backfillDimensionPath(path, leafValues, &leafIndex, dimension);
+}
+
+void backfillDimensionPath(ConfigMetricsReportList *config_report_list) {
+ for (int i = 0; i < config_report_list->reports_size(); ++i) {
+ auto report = config_report_list->mutable_reports(i);
+ for (int j = 0; j < report->metrics_size(); ++j) {
+ auto metric_report = report->mutable_metrics(j);
+ if (metric_report->has_dimensions_path_in_what() ||
+ metric_report->has_dimensions_path_in_condition()) {
+ auto whatPath = metric_report->dimensions_path_in_what();
+ auto conditionPath = metric_report->dimensions_path_in_condition();
+ if (metric_report->has_count_metrics()) {
+ backfillDimensionPath(whatPath, conditionPath,
+ metric_report->mutable_count_metrics());
+ } else if (metric_report->has_duration_metrics()) {
+ backfillDimensionPath(whatPath, conditionPath,
+ metric_report->mutable_duration_metrics());
+ } else if (metric_report->has_gauge_metrics()) {
+ backfillDimensionPath(whatPath, conditionPath,
+ metric_report->mutable_gauge_metrics());
+ } else if (metric_report->has_value_metrics()) {
+ backfillDimensionPath(whatPath, conditionPath,
+ metric_report->mutable_value_metrics());
+ }
+ metric_report->clear_dimensions_path_in_what();
+ metric_report->clear_dimensions_path_in_condition();
+ }
+ }
+ }
+}
+
+void backfillStartEndTimestamp(StatsLogReport *report) {
+ const int64_t timeBaseNs = report->time_base_elapsed_nano_seconds();
+ const int64_t bucketSizeNs = report->bucket_size_nano_seconds();
+ if (report->has_count_metrics()) {
+ backfillStartEndTimestampForMetrics(
+ timeBaseNs, bucketSizeNs, report->mutable_count_metrics());
+ } else if (report->has_duration_metrics()) {
+ backfillStartEndTimestampForMetrics(
+ timeBaseNs, bucketSizeNs, report->mutable_duration_metrics());
+ } else if (report->has_gauge_metrics()) {
+ backfillStartEndTimestampForMetrics(
+ timeBaseNs, bucketSizeNs, report->mutable_gauge_metrics());
+ if (report->gauge_metrics().skipped_size() > 0) {
+ backfillStartEndTimestampForSkippedBuckets(
+ timeBaseNs, report->mutable_gauge_metrics());
+ }
+ } else if (report->has_value_metrics()) {
+ backfillStartEndTimestampForMetrics(
+ timeBaseNs, bucketSizeNs, report->mutable_value_metrics());
+ if (report->value_metrics().skipped_size() > 0) {
+ backfillStartEndTimestampForSkippedBuckets(
+ timeBaseNs, report->mutable_value_metrics());
+ }
+ }
+}
+
+void backfillStartEndTimestamp(ConfigMetricsReport *config_report) {
+ for (int j = 0; j < config_report->metrics_size(); ++j) {
+ backfillStartEndTimestamp(config_report->mutable_metrics(j));
+ }
+}
+
+void backfillStartEndTimestamp(ConfigMetricsReportList *config_report_list) {
+ for (int i = 0; i < config_report_list->reports_size(); ++i) {
+ backfillStartEndTimestamp(config_report_list->mutable_reports(i));
+ }
+}
+
} // namespace statsd
} // namespace os
} // namespace android \ No newline at end of file
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index 6ecca46862da..635c5835333a 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -19,12 +19,16 @@
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "src/StatsLogProcessor.h"
#include "src/logd/LogEvent.h"
+#include "src/hash.h"
+#include "src/stats_log_util.h"
#include "statslog.h"
namespace android {
namespace os {
namespace statsd {
+using google::protobuf::RepeatedPtrField;
+
// Create AtomMatcher proto to simply match a specific atom type.
AtomMatcher CreateSimpleAtomMatcher(const string& name, int atomId);
@@ -201,6 +205,53 @@ struct DimensionsPair {
bool LessThan(const DimensionsValue& s1, const DimensionsValue& s2);
bool LessThan(const DimensionsPair& s1, const DimensionsPair& s2);
+
+void backfillStartEndTimestamp(ConfigMetricsReport *config_report);
+void backfillStartEndTimestamp(ConfigMetricsReportList *config_report_list);
+
+void backfillStringInReport(ConfigMetricsReportList *config_report_list);
+void backfillStringInDimension(const std::map<uint64_t, string>& str_map,
+ DimensionsValue* dimension);
+
+template <typename T>
+void backfillStringInDimension(const std::map<uint64_t, string>& str_map,
+ T* metrics) {
+ for (int i = 0; i < metrics->data_size(); ++i) {
+ auto data = metrics->mutable_data(i);
+ if (data->has_dimensions_in_what()) {
+ backfillStringInDimension(str_map, data->mutable_dimensions_in_what());
+ }
+ if (data->has_dimensions_in_condition()) {
+ backfillStringInDimension(str_map, data->mutable_dimensions_in_condition());
+ }
+ }
+}
+
+void backfillDimensionPath(ConfigMetricsReportList* config_report_list);
+
+bool backfillDimensionPath(const DimensionsValue& path,
+ const google::protobuf::RepeatedPtrField<DimensionsValue>& leafValues,
+ DimensionsValue* dimension);
+
+template <typename T>
+void backfillDimensionPath(const DimensionsValue& whatPath,
+ const DimensionsValue& conditionPath,
+ T* metricData) {
+ for (int i = 0; i < metricData->data_size(); ++i) {
+ auto data = metricData->mutable_data(i);
+ if (data->dimension_leaf_values_in_what_size() > 0) {
+ backfillDimensionPath(whatPath, data->dimension_leaf_values_in_what(),
+ data->mutable_dimensions_in_what());
+ data->clear_dimension_leaf_values_in_what();
+ }
+ if (data->dimension_leaf_values_in_condition_size() > 0) {
+ backfillDimensionPath(conditionPath, data->dimension_leaf_values_in_condition(),
+ data->mutable_dimensions_in_condition());
+ data->clear_dimension_leaf_values_in_condition();
+ }
+ }
+}
+
struct DimensionCompare {
bool operator()(const DimensionsPair& s1, const DimensionsPair& s2) const {
return LessThan(s1, s2);
@@ -221,6 +272,51 @@ void sortMetricDataByDimensionsValue(const T& metricData, T* sortedMetricData) {
}
}
+template <typename T>
+void backfillStartEndTimestampForFullBucket(
+ const int64_t timeBaseNs, const int64_t bucketSizeNs, T* bucket) {
+ bucket->set_start_bucket_elapsed_nanos(timeBaseNs + bucketSizeNs * bucket->bucket_num());
+ bucket->set_end_bucket_elapsed_nanos(
+ timeBaseNs + bucketSizeNs * bucket->bucket_num() + bucketSizeNs);
+ bucket->clear_bucket_num();
+}
+
+template <typename T>
+void backfillStartEndTimestampForPartialBucket(const int64_t timeBaseNs, T* bucket) {
+ if (bucket->has_start_bucket_elapsed_millis()) {
+ bucket->set_start_bucket_elapsed_nanos(
+ MillisToNano(bucket->start_bucket_elapsed_millis()));
+ bucket->clear_start_bucket_elapsed_millis();
+ }
+ if (bucket->has_end_bucket_elapsed_millis()) {
+ bucket->set_end_bucket_elapsed_nanos(
+ MillisToNano(bucket->end_bucket_elapsed_millis()));
+ bucket->clear_end_bucket_elapsed_millis();
+ }
+}
+
+template <typename T>
+void backfillStartEndTimestampForMetrics(const int64_t timeBaseNs, const int64_t bucketSizeNs,
+ T* metrics) {
+ for (int i = 0; i < metrics->data_size(); ++i) {
+ auto data = metrics->mutable_data(i);
+ for (int j = 0; j < data->bucket_info_size(); ++j) {
+ auto bucket = data->mutable_bucket_info(j);
+ if (bucket->has_bucket_num()) {
+ backfillStartEndTimestampForFullBucket(timeBaseNs, bucketSizeNs, bucket);
+ } else {
+ backfillStartEndTimestampForPartialBucket(timeBaseNs, bucket);
+ }
+ }
+ }
+}
+
+template <typename T>
+void backfillStartEndTimestampForSkippedBuckets(const int64_t timeBaseNs, T* metrics) {
+ for (int i = 0; i < metrics->skipped_size(); ++i) {
+ backfillStartEndTimestampForPartialBucket(timeBaseNs, metrics->mutable_skipped(i));
+ }
+}
} // namespace statsd
} // namespace os
} // namespace android \ No newline at end of file
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 622847334292..88dec3a579c4 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -31,7 +31,10 @@ Landroid/app/Activity;->getActivityOptions()Landroid/app/ActivityOptions;
Landroid/app/Activity;->getActivityToken()Landroid/os/IBinder;
Landroid/app/Activity;->mActivityInfo:Landroid/content/pm/ActivityInfo;
Landroid/app/Activity;->mApplication:Landroid/app/Application;
+Landroid/app/Activity;->mCalled:Z
Landroid/app/Activity;->mComponent:Landroid/content/ComponentName;
+Landroid/app/Activity;->mConfigChangeFlags:I
+Landroid/app/Activity;->mCurrentConfig:Landroid/content/res/Configuration;
Landroid/app/Activity;->mFinished:Z
Landroid/app/Activity;->mFragments:Landroid/app/FragmentController;
Landroid/app/Activity;->mHandler:Landroid/os/Handler;
@@ -41,6 +44,7 @@ Landroid/app/Activity;->mReferrer:Ljava/lang/String;
Landroid/app/Activity;->mResultCode:I
Landroid/app/Activity;->mResultData:Landroid/content/Intent;
Landroid/app/Activity;->mResumed:Z
+Landroid/app/Activity;->mTitle:Ljava/lang/CharSequence;
Landroid/app/Activity;->mToken:Landroid/os/IBinder;
Landroid/app/Activity;->mWindow:Landroid/view/Window;
Landroid/app/Activity;->mWindowManager:Landroid/view/WindowManager;
@@ -406,14 +410,12 @@ Landroid/app/NativeActivity;->showIme(I)V
Landroid/app/Notification$Action;->mIcon:Landroid/graphics/drawable/Icon;
Landroid/app/Notification$Builder;->mActions:Ljava/util/ArrayList;
Landroid/app/Notification$Builder;->makePublicContentView()Landroid/widget/RemoteViews;
-Landroid/app/Notification$Builder;->setChannel(Ljava/lang/String;)Landroid/app/Notification$Builder;
Landroid/app/Notification;-><init>(Landroid/content/Context;ILjava/lang/CharSequence;JLjava/lang/CharSequence;Ljava/lang/CharSequence;Landroid/content/Intent;)V
Landroid/app/Notification;->isGroupSummary()Z
Landroid/app/Notification;->mChannelId:Ljava/lang/String;
Landroid/app/Notification;->mGroupKey:Ljava/lang/String;
Landroid/app/Notification;->mLargeIcon:Landroid/graphics/drawable/Icon;
Landroid/app/Notification;->mSmallIcon:Landroid/graphics/drawable/Icon;
-Landroid/app/Notification;->setLatestEventInfo(Landroid/content/Context;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Landroid/app/PendingIntent;)V
Landroid/app/Notification;->setSmallIcon(Landroid/graphics/drawable/Icon;)V
Landroid/app/NotificationManager;->getService()Landroid/app/INotificationManager;
Landroid/app/NotificationManager;->notifyAsUser(Ljava/lang/String;ILandroid/app/Notification;Landroid/os/UserHandle;)V
@@ -446,11 +448,6 @@ Landroid/app/Service;->setForeground(Z)V
Landroid/app/SharedPreferencesImpl;-><init>(Ljava/io/File;I)V
Landroid/app/SharedPreferencesImpl;->mFile:Ljava/io/File;
Landroid/app/SharedPreferencesImpl;->startReloadIfChangedUnexpectedly()V
-Landroid/app/slice/Slice$Builder;-><init>(Landroid/net/Uri;)V
-Landroid/app/slice/Slice$Builder;->setSpec(Landroid/app/slice/SliceSpec;)Landroid/app/slice/Slice$Builder;
-Landroid/app/slice/SliceItem;->getTimestamp()J
-Landroid/app/slice/SliceManager;->bindSlice(Landroid/net/Uri;Ljava/util/List;)Landroid/app/slice/Slice;
-Landroid/app/slice/SliceManager;->pinSlice(Landroid/net/Uri;Ljava/util/List;)V
Landroid/app/StatusBarManager;->collapsePanels()V
Landroid/app/StatusBarManager;->disable(I)V
Landroid/app/StatusBarManager;->expandNotificationsPanel()V
@@ -701,6 +698,7 @@ Landroid/content/pm/IPackageDataObserver;->onRemoveCompleted(Ljava/lang/String;Z
Landroid/content/pm/IPackageDeleteObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageDeleteObserver;
Landroid/content/pm/IPackageDeleteObserver2$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/pm/IPackageDeleteObserver2$Stub$Proxy;->mRemote:Landroid/os/IBinder;
+Landroid/content/pm/IPackageDeleteObserver2$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageDeleteObserver2;
Landroid/content/pm/IPackageDeleteObserver2;->onPackageDeleted(Ljava/lang/String;ILjava/lang/String;)V
Landroid/content/pm/IPackageInstallerCallback$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/pm/IPackageInstallerCallback$Stub$Proxy;->mRemote:Landroid/os/IBinder;
@@ -805,6 +803,7 @@ Landroid/content/pm/PackageParser$Package;->mKeySetMapping:Landroid/util/ArrayMa
Landroid/content/pm/PackageParser$Package;->mPreferredOrder:I
Landroid/content/pm/PackageParser$Package;->mSharedUserId:Ljava/lang/String;
Landroid/content/pm/PackageParser$Package;->mSharedUserLabel:I
+Landroid/content/pm/PackageParser$Package;->mSigningDetails:Landroid/content/pm/PackageParser$SigningDetails;
Landroid/content/pm/PackageParser$Package;->mVersionCode:I
Landroid/content/pm/PackageParser$Package;->mVersionName:Ljava/lang/String;
Landroid/content/pm/PackageParser$Package;->packageName:Ljava/lang/String;
@@ -821,6 +820,7 @@ Landroid/content/pm/PackageParser$Provider;->info:Landroid/content/pm/ProviderIn
Landroid/content/pm/PackageParser$ProviderIntentInfo;->provider:Landroid/content/pm/PackageParser$Provider;
Landroid/content/pm/PackageParser$Service;->info:Landroid/content/pm/ServiceInfo;
Landroid/content/pm/PackageParser$ServiceIntentInfo;->service:Landroid/content/pm/PackageParser$Service;
+Landroid/content/pm/PackageParser$SigningDetails;->signatures:[Landroid/content/pm/Signature;
Landroid/content/pm/PackageParser;-><init>()V
Landroid/content/pm/PackageParser;->collectCertificates(Landroid/content/pm/PackageParser$Package;Ljava/io/File;Z)V
Landroid/content/pm/PackageParser;->collectCertificates(Landroid/content/pm/PackageParser$Package;Z)V
@@ -839,7 +839,6 @@ Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;I)Landroid/conten
Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;IZ)Landroid/content/pm/PackageParser$Package;
Landroid/content/pm/PackageUserState;-><init>()V
Landroid/content/pm/ParceledListSlice;-><init>(Ljava/util/List;)V
-Landroid/content/pm/ResolveInfo;->instantAppAvailable:Z
Landroid/content/pm/ShortcutManager;->mService:Landroid/content/pm/IShortcutService;
Landroid/content/pm/Signature;->getPublicKey()Ljava/security/PublicKey;
Landroid/content/pm/UserInfo;-><init>(ILjava/lang/String;I)V
@@ -884,6 +883,7 @@ Landroid/content/res/CompatibilityInfo;->DEFAULT_COMPATIBILITY_INFO:Landroid/con
Landroid/content/res/DrawableCache;-><init>()V
Landroid/content/res/DrawableCache;->getInstance(JLandroid/content/res/Resources;Landroid/content/res/Resources$Theme;)Landroid/graphics/drawable/Drawable;
Landroid/content/res/ObbInfo;->salt:[B
+Landroid/content/res/Resources$Theme;->mThemeImpl:Landroid/content/res/ResourcesImpl$ThemeImpl;
Landroid/content/res/Resources;->getCompatibilityInfo()Landroid/content/res/CompatibilityInfo;
Landroid/content/res/Resources;->loadXmlResourceParser(ILjava/lang/String;)Landroid/content/res/XmlResourceParser;
Landroid/content/res/Resources;->loadXmlResourceParser(Ljava/lang/String;IILjava/lang/String;)Landroid/content/res/XmlResourceParser;
@@ -960,7 +960,6 @@ Landroid/content/UriMatcher;->mChildren:Ljava/util/ArrayList;
Landroid/content/UriMatcher;->mText:Ljava/lang/String;
Landroid/database/AbstractCursor;->mExtras:Landroid/os/Bundle;
Landroid/database/AbstractCursor;->mNotifyUri:Landroid/net/Uri;
-Landroid/database/AbstractCursor;->mRowIdColumnIndex:I
Landroid/database/AbstractWindowedCursor;->clearOrCreateWindow(Ljava/lang/String;)V
Landroid/database/CursorWindow;->mWindowPtr:J
Landroid/database/CursorWindow;->sCursorWindowSize:I
@@ -981,8 +980,6 @@ Landroid/database/sqlite/SQLiteOpenHelper;->mName:Ljava/lang/String;
Landroid/database/sqlite/SQLiteStatement;-><init>(Landroid/database/sqlite/SQLiteDatabase;Ljava/lang/String;[Ljava/lang/Object;)V
Landroid/ddm/DdmHandleAppName;->getAppName()Ljava/lang/String;
Landroid/ddm/DdmHandleAppName;->setAppName(Ljava/lang/String;I)V
-Landroid/graphics/AvoidXfermode$Mode;->AVOID:Landroid/graphics/AvoidXfermode$Mode;
-Landroid/graphics/AvoidXfermode$Mode;->TARGET:Landroid/graphics/AvoidXfermode$Mode;
Landroid/graphics/BaseCanvas;->mNativeCanvasWrapper:J
Landroid/graphics/Bitmap$Config;->nativeInt:I
Landroid/graphics/Bitmap$Config;->nativeToConfig(I)Landroid/graphics/Bitmap$Config;
@@ -1003,7 +1000,6 @@ Landroid/graphics/BitmapRegionDecoder;-><init>(J)V
Landroid/graphics/Camera;->native_instance:J
Landroid/graphics/Canvas;-><init>(J)V
Landroid/graphics/Canvas;->release()V
-Landroid/graphics/Canvas;->save(I)I
Landroid/graphics/ColorMatrixColorFilter;->setColorMatrix(Landroid/graphics/ColorMatrix;)V
Landroid/graphics/drawable/AnimatedImageDrawable;->onAnimationEnd()V
Landroid/graphics/drawable/AnimatedStateListDrawable$AnimatedStateListState;->mStateIds:Landroid/util/SparseIntArray;
@@ -1087,10 +1083,10 @@ Landroid/graphics/GraphicBuffer;->createFromExisting(IIIIJ)Landroid/graphics/Gra
Landroid/graphics/GraphicBuffer;->CREATOR:Landroid/os/Parcelable$Creator;
Landroid/graphics/GraphicBuffer;->mNativeObject:J
Landroid/graphics/ImageDecoder;->postProcessAndRelease(Landroid/graphics/Canvas;)I
+Landroid/graphics/Insets;->bottom:I
Landroid/graphics/Insets;->left:I
-Landroid/graphics/Insets;->top:I
Landroid/graphics/Insets;->right:I
-Landroid/graphics/Insets;->bottom:I
+Landroid/graphics/Insets;->top:I
Landroid/graphics/LinearGradient;->mColors:[I
Landroid/graphics/Matrix;->native_instance:J
Landroid/graphics/Movie;-><init>(J)V
@@ -1098,7 +1094,6 @@ Landroid/graphics/Movie;->mNativeMovie:J
Landroid/graphics/NinePatch$InsetStruct;-><init>(IIIIIIIIFIF)V
Landroid/graphics/NinePatch;->mBitmap:Landroid/graphics/Bitmap;
Landroid/graphics/Picture;->mNativePicture:J
-Landroid/graphics/PixelXorXfermode;-><init>(I)V
Landroid/graphics/PorterDuffColorFilter;->getColor()I
Landroid/graphics/PorterDuffColorFilter;->setColor(I)V
Landroid/graphics/PorterDuffColorFilter;->setMode(Landroid/graphics/PorterDuff$Mode;)V
@@ -1195,6 +1190,7 @@ Landroid/hardware/display/WifiDisplayStatus;->mActiveDisplay:Landroid/hardware/d
Landroid/hardware/display/WifiDisplayStatus;->mDisplays:[Landroid/hardware/display/WifiDisplay;
Landroid/hardware/fingerprint/Fingerprint;->getFingerId()I
Landroid/hardware/fingerprint/Fingerprint;->getName()Ljava/lang/CharSequence;
+Landroid/hardware/fingerprint/FingerprintManager;->getEnrolledFingerprints()Ljava/util/List;
Landroid/hardware/fingerprint/IFingerprintService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/hardware/HardwareBuffer;-><init>(J)V
Landroid/hardware/HardwareBuffer;->mNativeObject:J
@@ -1465,6 +1461,7 @@ Landroid/media/session/MediaSession;->mCallback:Landroid/media/session/MediaSess
Landroid/media/session/MediaSessionLegacyHelper;->getHelper(Landroid/content/Context;)Landroid/media/session/MediaSessionLegacyHelper;
Landroid/media/soundtrigger/SoundTriggerDetector$EventPayload;->getCaptureSession()Ljava/lang/Integer;
Landroid/media/soundtrigger/SoundTriggerDetector$EventPayload;->getData()[B
+Landroid/media/soundtrigger/SoundTriggerManager;->isRecognitionActive(Ljava/util/UUID;)Z
Landroid/media/soundtrigger/SoundTriggerManager;->loadSoundModel(Landroid/hardware/soundtrigger/SoundTrigger$SoundModel;)I
Landroid/media/soundtrigger/SoundTriggerManager;->startRecognition(Ljava/util/UUID;Landroid/app/PendingIntent;Landroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;)I
Landroid/media/soundtrigger/SoundTriggerManager;->startRecognition(Ljava/util/UUID;Landroid/os/Bundle;Landroid/content/ComponentName;Landroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;)I
@@ -1505,7 +1502,6 @@ Landroid/net/ConnectivityManager;->isNetworkSupported(I)Z
Landroid/net/ConnectivityManager;->isNetworkTypeMobile(I)Z
Landroid/net/ConnectivityManager;->mService:Landroid/net/IConnectivityManager;
Landroid/net/ConnectivityManager;->registerNetworkFactory(Landroid/os/Messenger;Ljava/lang/String;)V
-Landroid/net/ConnectivityManager;->requestRouteToHost(II)Z
Landroid/net/ConnectivityManager;->requestRouteToHostAddress(ILjava/net/InetAddress;)Z
Landroid/net/ConnectivityManager;->setBackgroundDataSetting(Z)V
Landroid/net/ConnectivityManager;->TYPE_MOBILE_CBS:I
@@ -1565,7 +1561,6 @@ Landroid/net/SSLCertificateSocketFactory;-><init>(ILandroid/net/SSLSessionCache;
Landroid/net/SSLCertificateSocketFactory;->castToOpenSSLSocket(Ljava/net/Socket;)Lcom/android/org/conscrypt/OpenSSLSocketImpl;
Landroid/net/SSLCertificateSocketFactory;->getAlpnSelectedProtocol(Ljava/net/Socket;)[B
Landroid/net/SSLCertificateSocketFactory;->getDelegate()Ljavax/net/ssl/SSLSocketFactory;
-Landroid/net/SSLCertificateSocketFactory;->getHttpSocketFactory(ILandroid/net/SSLSessionCache;)Lorg/apache/http/conn/ssl/SSLSocketFactory;
Landroid/net/SSLCertificateSocketFactory;->INSECURE_TRUST_MANAGER:[Ljavax/net/ssl/TrustManager;
Landroid/net/SSLCertificateSocketFactory;->isSslCheckRelaxed()Z
Landroid/net/SSLCertificateSocketFactory;->makeSocketFactory([Ljavax/net/ssl/KeyManager;[Ljavax/net/ssl/TrustManager;)Ljavax/net/ssl/SSLSocketFactory;
@@ -1633,7 +1628,6 @@ Landroid/net/wifi/ScanResult;->hessid:J
Landroid/net/wifi/ScanResult;->informationElements:[Landroid/net/wifi/ScanResult$InformationElement;
Landroid/net/wifi/ScanResult;->numUsage:I
Landroid/net/wifi/ScanResult;->seen:J
-Landroid/net/wifi/ScanResult;->untrusted:Z
Landroid/net/wifi/ScanResult;->wifiSsid:Landroid/net/wifi/WifiSsid;
Landroid/net/wifi/WifiConfiguration;->apBand:I
Landroid/net/wifi/WifiConfiguration;->apChannel:I
@@ -1827,9 +1821,7 @@ Landroid/os/PowerManager;->getMaximumScreenBrightnessSetting()I
Landroid/os/PowerManager;->getMinimumScreenBrightnessSetting()I
Landroid/os/PowerManager;->isLightDeviceIdleMode()Z
Landroid/os/PowerManager;->mService:Landroid/os/IPowerManager;
-Landroid/os/PowerManager;->userActivity(JZ)V
Landroid/os/PowerManager;->validateWakeLockParameters(ILjava/lang/String;)V
-Landroid/os/PowerManager;->wakeUp(J)V
Landroid/os/PowerManager;->wakeUp(JLjava/lang/String;)V
Landroid/os/Process;->getFreeMemory()J
Landroid/os/Process;->getParentPid(I)I
@@ -1863,11 +1855,9 @@ Landroid/os/storage/IStorageManager$Stub;->asInterface(Landroid/os/IBinder;)Land
Landroid/os/storage/StorageManager;->findVolumeByUuid(Ljava/lang/String;)Landroid/os/storage/VolumeInfo;
Landroid/os/storage/StorageManager;->getBestVolumeDescription(Landroid/os/storage/VolumeInfo;)Ljava/lang/String;
Landroid/os/storage/StorageManager;->getDisks()Ljava/util/List;
-Landroid/os/storage/StorageManager;->getPrimaryVolume()Landroid/os/storage/StorageVolume;
Landroid/os/storage/StorageManager;->getStorageBytesUntilLow(Ljava/io/File;)J
Landroid/os/storage/StorageManager;->getStorageFullBytes(Ljava/io/File;)J
Landroid/os/storage/StorageManager;->getStorageLowBytes(Ljava/io/File;)J
-Landroid/os/storage/StorageManager;->getVolumeList()[Landroid/os/storage/StorageVolume;
Landroid/os/storage/StorageManager;->getVolumeList(II)[Landroid/os/storage/StorageVolume;
Landroid/os/storage/StorageManager;->getVolumePaths()[Ljava/lang/String;
Landroid/os/storage/StorageManager;->getVolumes()Ljava/util/List;
@@ -1890,12 +1880,12 @@ Landroid/os/storage/VolumeInfo;->isVisible()Z
Landroid/os/storage/VolumeInfo;->TYPE_EMULATED:I
Landroid/os/storage/VolumeInfo;->TYPE_PUBLIC:I
Landroid/os/StrictMode$Span;->finish()V
-Landroid/os/StrictMode$ThreadPolicy$Builder;->penaltyListener(Landroid/os/StrictMode$OnThreadViolationListener;Ljava/util/concurrent/Executor;)Landroid/os/StrictMode$ThreadPolicy$Builder;
Landroid/os/StrictMode;->conditionallyCheckInstanceCounts()V
Landroid/os/StrictMode;->disableDeathOnFileUriExposure()V
Landroid/os/StrictMode;->enterCriticalSpan(Ljava/lang/String;)Landroid/os/StrictMode$Span;
Landroid/os/StrictMode;->getThreadPolicyMask()I
Landroid/os/StrictMode;->onBinderStrictModePolicyChange(I)V
+Landroid/os/StrictMode;->sLastVmViolationTime:Ljava/util/HashMap;
Landroid/os/StrictMode;->violationsBeingTimed:Ljava/lang/ThreadLocal;
Landroid/os/SystemProperties;-><init>()V
Landroid/os/SystemProperties;->addChangeCallback(Ljava/lang/Runnable;)V
@@ -1942,7 +1932,6 @@ Landroid/os/UserHandle;->USER_OWNER:I
Landroid/os/UserHandle;->USER_SERIAL_SYSTEM:I
Landroid/os/UserHandle;->USER_SYSTEM:I
Landroid/os/UserManager;->get(Landroid/content/Context;)Landroid/os/UserManager;
-Landroid/os/UserManager;->getBadgedLabelForUser(Ljava/lang/CharSequence;Landroid/os/UserHandle;)Ljava/lang/CharSequence;
Landroid/os/UserManager;->getMaxSupportedUsers()I
Landroid/os/UserManager;->getProfiles(I)Ljava/util/List;
Landroid/os/UserManager;->getUserHandle()I
@@ -2017,17 +2006,8 @@ Landroid/preference/PreferenceScreen;->mRootAdapter:Landroid/widget/ListAdapter;
Landroid/print/PrinterId;->getServiceName()Landroid/content/ComponentName;
Landroid/print/PrintJobInfo;->getAdvancedOptions()Landroid/os/Bundle;
Landroid/print/PrintJobInfo;->getDocumentInfo()Landroid/print/PrintDocumentInfo;
-Landroid/provider/Browser$BookmarkColumns;->DATE:Ljava/lang/String;
-Landroid/provider/Browser;->BOOKMARKS_URI:Landroid/net/Uri;
-Landroid/provider/Browser;->canClearHistory(Landroid/content/ContentResolver;)Z
-Landroid/provider/Browser;->clearHistory(Landroid/content/ContentResolver;)V
-Landroid/provider/Browser;->clearSearches(Landroid/content/ContentResolver;)V
-Landroid/provider/Browser;->deleteFromHistory(Landroid/content/ContentResolver;Ljava/lang/String;)V
Landroid/provider/Browser;->getVisitedHistory(Landroid/content/ContentResolver;)[Ljava/lang/String;
-Landroid/provider/Browser;->HISTORY_PROJECTION:[Ljava/lang/String;
-Landroid/provider/Browser;->SEARCHES_URI:Landroid/net/Uri;
Landroid/provider/Browser;->sendString(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)V
-Landroid/provider/Browser;->updateVisitedHistory(Landroid/content/ContentResolver;Ljava/lang/String;Z)V
Landroid/provider/CalendarContract$CalendarAlerts;->findNextAlarmTime(Landroid/content/ContentResolver;J)J
Landroid/provider/CalendarContract$CalendarAlerts;->rescheduleMissedAlarms(Landroid/content/ContentResolver;Landroid/content/Context;Landroid/app/AlarmManager;)V
Landroid/provider/Downloads$Impl$RequestHeaders;->INSERT_KEY_PREFIX:Ljava/lang/String;
@@ -2073,7 +2053,6 @@ 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;->SCREEN_AUTO_BRIGHTNESS_ADJ:Ljava/lang/String;
Landroid/provider/Settings$System;->sNameValueCache:Landroid/provider/Settings$NameValueCache;
-Landroid/provider/Settings$System;->VOLUME_SETTINGS:[Ljava/lang/String;
Landroid/provider/Settings;->isCallingPackageAllowedToDrawOverlays(Landroid/content/Context;ILjava/lang/String;Z)Z
Landroid/provider/Settings;->isCallingPackageAllowedToWriteSettings(Landroid/content/Context;ILjava/lang/String;Z)Z
Landroid/provider/Telephony$Sms$Inbox;->addMessage(ILandroid/content/ContentResolver;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;Z)Landroid/net/Uri;
@@ -2282,7 +2261,6 @@ Landroid/renderscript/RenderScript;->getMinorID()J
Landroid/renderscript/RenderScriptCacheDir;->mCacheDir:Ljava/io/File;
Landroid/renderscript/RenderScriptCacheDir;->setupDiskCache(Ljava/io/File;)V
Landroid/security/keystore/AndroidKeyStoreProvider;->getKeyStoreOperationHandle(Ljava/lang/Object;)J
-Landroid/security/keystore/recovery/RecoveryController;->initRecoveryService(Ljava/lang/String;[B)V
Landroid/security/KeyStore;->getInstance()Landroid/security/KeyStore;
Landroid/security/net/config/RootTrustManager;->checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
Landroid/service/media/IMediaBrowserServiceCallbacks$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/media/IMediaBrowserServiceCallbacks;
@@ -2294,8 +2272,6 @@ Landroid/service/media/MediaBrowserService$Result;->mFlags:I
Landroid/service/media/MediaBrowserService;->KEY_MEDIA_ITEM:Ljava/lang/String;
Landroid/service/notification/NotificationListenerService;->isBound()Z
Landroid/service/notification/NotificationListenerService;->mHandler:Landroid/os/Handler;
-Landroid/service/notification/NotificationListenerService;->registerAsSystemService(Landroid/content/Context;Landroid/content/ComponentName;I)V
-Landroid/service/notification/NotificationListenerService;->unregisterAsSystemService()V
Landroid/service/notification/StatusBarNotification;->getInitialPid()I
Landroid/service/notification/StatusBarNotification;->getUid()I
Landroid/service/persistentdata/IPersistentDataBlockService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/persistentdata/IPersistentDataBlockService;
@@ -2364,6 +2340,9 @@ Landroid/telecom/AudioState;->isMuted:Z
Landroid/telecom/TelecomManager;->EXTRA_IS_HANDOVER:Ljava/lang/String;
Landroid/telecom/TelecomManager;->getUserSelectedOutgoingPhoneAccount()Landroid/telecom/PhoneAccountHandle;
Landroid/telecom/TelecomManager;->setUserSelectedOutgoingPhoneAccount(Landroid/telecom/PhoneAccountHandle;)V
+Landroid/telephony/CellIdentityGsm;->mBsic:I
+Landroid/telephony/CellSignalStrengthGsm;->mBitErrorRate:I
+Landroid/telephony/CellSignalStrengthGsm;->mSignalStrength:I
Landroid/telephony/CellSignalStrengthLte;->mCqi:I
Landroid/telephony/CellSignalStrengthLte;->mRsrp:I
Landroid/telephony/CellSignalStrengthLte;->mRsrq:I
@@ -2380,6 +2359,7 @@ Landroid/telephony/SignalStrength;->getAsuLevel()I
Landroid/telephony/SignalStrength;->getCdmaLevel()I
Landroid/telephony/SignalStrength;->getDbm()I
Landroid/telephony/SignalStrength;->getGsmDbm()I
+Landroid/telephony/SignalStrength;->getLteCqi()I
Landroid/telephony/SignalStrength;->getLteDbm()I
Landroid/telephony/SignalStrength;->getLteRsrp()I
Landroid/telephony/SignalStrength;->getLteRsrq()I
@@ -2397,6 +2377,8 @@ Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_GREAT:I
Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_MODERATE:I
Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_NONE_OR_UNKNOWN:I
Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_POOR:I
+Landroid/telephony/SmsManager;->deleteMessageFromIcc(I)Z
+Landroid/telephony/SmsManager;->getAllMessagesFromIcc()Ljava/util/ArrayList;
Landroid/telephony/SmsManager;->sendMultipartTextMessage(Ljava/lang/String;Ljava/lang/String;Ljava/util/ArrayList;Ljava/util/ArrayList;Ljava/util/ArrayList;IZI)V
Landroid/telephony/SmsManager;->sendTextMessage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/app/PendingIntent;Landroid/app/PendingIntent;IZI)V
Landroid/telephony/SmsMessage;->getSubId()I
@@ -2423,6 +2405,7 @@ Landroid/telephony/TelephonyManager;->getGroupIdLevel1(I)Ljava/lang/String;
Landroid/telephony/TelephonyManager;->getITelephony()Lcom/android/internal/telephony/ITelephony;
Landroid/telephony/TelephonyManager;->getLine1Number(I)Ljava/lang/String;
Landroid/telephony/TelephonyManager;->getMultiSimConfiguration()Landroid/telephony/TelephonyManager$MultiSimVariants;
+Landroid/telephony/TelephonyManager;->getNai(I)Ljava/lang/String;
Landroid/telephony/TelephonyManager;->getNetworkClass(I)I
Landroid/telephony/TelephonyManager;->getNetworkCountryIso(I)Ljava/lang/String;
Landroid/telephony/TelephonyManager;->getNetworkOperator(I)Ljava/lang/String;
@@ -2650,6 +2633,7 @@ Landroid/view/IWindowManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/vi
Landroid/view/IWindowManager;->getAnimationScale(I)F
Landroid/view/IWindowManager;->hasNavigationBar()Z
Landroid/view/IWindowManager;->setAnimationScale(IF)V
+Landroid/view/IWindowManager;->setAnimationScales([F)V
Landroid/view/IWindowManager;->setShelfHeight(ZI)V
Landroid/view/IWindowManager;->setStrictModeVisualIndicatorPreference(Ljava/lang/String;)V
Landroid/view/IWindowSession$Stub$Proxy;->relayout(Landroid/view/IWindow;ILandroid/view/WindowManager$LayoutParams;IIIIJLandroid/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
@@ -2798,7 +2782,6 @@ Landroid/view/View;->getVerticalScrollFactor()F
Landroid/view/View;->getViewRootImpl()Landroid/view/ViewRootImpl;
Landroid/view/View;->getWindowDisplayFrame(Landroid/graphics/Rect;)V
Landroid/view/View;->includeForAccessibility()Z
-Landroid/view/View;->initializeScrollbars(Landroid/content/res/TypedArray;)V
Landroid/view/View;->internalSetPadding(IIII)V
Landroid/view/View;->invalidateParentIfNeeded()V
Landroid/view/View;->isPaddingResolved()Z
@@ -2866,7 +2849,6 @@ Landroid/view/View;->transformMatrixToGlobal(Landroid/graphics/Matrix;)V
Landroid/view/View;->transformMatrixToLocal(Landroid/graphics/Matrix;)V
Landroid/view/ViewConfiguration;->getDeviceGlobalActionKeyTimeout()J
Landroid/view/ViewConfiguration;->getDoubleTapMinTime()I
-Landroid/view/ViewConfiguration;->getScaledScrollFactor()I
Landroid/view/ViewConfiguration;->mFadingMarqueeEnabled:Z
Landroid/view/ViewConfiguration;->sHasPermanentMenuKey:Z
Landroid/view/ViewConfiguration;->sHasPermanentMenuKeySet:Z
@@ -2958,6 +2940,7 @@ Landroid/webkit/CacheManager;->getCacheFileBaseDir()Ljava/io/File;
Landroid/webkit/CacheManager;->saveCacheFile(Ljava/lang/String;Landroid/webkit/CacheManager$CacheResult;)V
Landroid/webkit/CacheManager;->startCacheTransaction()Z
Landroid/webkit/IWebViewUpdateService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Landroid/webkit/IWebViewUpdateService$Stub$Proxy;->waitForAndGetProvider()Landroid/webkit/WebViewProviderResponse;
Landroid/webkit/WebResourceResponse;->mImmutable:Z
Landroid/webkit/WebSettings$TextSize;->value:I
Landroid/webkit/WebSyncManager;->mHandler:Landroid/os/Handler;
@@ -2970,12 +2953,12 @@ Landroid/webkit/WebView;->getTouchIconUrl()Ljava/lang/String;
Landroid/webkit/WebView;->getVisibleTitleHeight()I
Landroid/webkit/WebView;->isPaused()Z
Landroid/webkit/WebView;->mProvider:Landroid/webkit/WebViewProvider;
+Landroid/webkit/WebView;->mWebViewThread:Landroid/os/Looper;
Landroid/webkit/WebView;->notifyFindDialogDismissed()V
Landroid/webkit/WebView;->onDrawVerticalScrollBar(Landroid/graphics/Canvas;Landroid/graphics/drawable/Drawable;IIII)V
Landroid/webkit/WebView;->restorePicture(Landroid/os/Bundle;Ljava/io/File;)Z
Landroid/webkit/WebView;->savePicture(Landroid/os/Bundle;Ljava/io/File;)Z
Landroid/webkit/WebView;->sEnforceThreadChecking:Z
-Landroid/webkit/WebViewClient;->onUnhandledInputEvent(Landroid/webkit/WebView;Landroid/view/InputEvent;)V
Landroid/webkit/WebViewDelegate;-><init>()V
Landroid/webkit/WebViewFactory;->getProvider()Landroid/webkit/WebViewFactoryProvider;
Landroid/webkit/WebViewFactory;->getUpdateService()Landroid/webkit/IWebViewUpdateService;
@@ -3046,7 +3029,9 @@ Landroid/widget/CursorAdapter;->mRowIDColumn:I
Landroid/widget/DatePicker;->mDelegate:Landroid/widget/DatePicker$DatePickerDelegate;
Landroid/widget/EdgeEffect;->mPaint:Landroid/graphics/Paint;
Landroid/widget/Editor;->invalidateTextDisplayList()V
+Landroid/widget/Editor;->mInsertionControllerEnabled:Z
Landroid/widget/Editor;->mSelectHandleLeft:Landroid/graphics/drawable/Drawable;
+Landroid/widget/Editor;->mSelectionControllerEnabled:Z
Landroid/widget/Editor;->mShowCursor:J
Landroid/widget/Editor;->mShowSoftInputOnFocus:Z
Landroid/widget/ExpandableListView;->mChildDivider:Landroid/graphics/drawable/Drawable;
@@ -3096,8 +3081,6 @@ Landroid/widget/ListPopupWindow;->setForceIgnoreOutsideTouch(Z)V
Landroid/widget/ListView;->fillDown(II)Landroid/view/View;
Landroid/widget/ListView;->fillSpecific(II)Landroid/view/View;
Landroid/widget/ListView;->fillUp(II)Landroid/view/View;
-Landroid/widget/ListView;->findViewTraversal(I)Landroid/view/View;
-Landroid/widget/ListView;->findViewWithTagTraversal(Ljava/lang/Object;)Landroid/view/View;
Landroid/widget/ListView;->mAreAllItemsSelectable:Z
Landroid/widget/ListView;->mFooterViewInfos:Ljava/util/ArrayList;
Landroid/widget/ListView;->mHeaderViewInfos:Ljava/util/ArrayList;
@@ -3106,8 +3089,11 @@ Landroid/widget/MediaController;->mAnchor:Landroid/view/View;
Landroid/widget/MediaController;->mDecor:Landroid/view/View;
Landroid/widget/MediaController;->mDecorLayoutParams:Landroid/view/WindowManager$LayoutParams;
Landroid/widget/MediaController;->mWindowManager:Landroid/view/WindowManager;
+Landroid/widget/NumberPicker;->initializeSelectorWheelIndices()V
Landroid/widget/NumberPicker;->mInputText:Landroid/widget/EditText;
+Landroid/widget/NumberPicker;->mMaxValue:I
Landroid/widget/NumberPicker;->mSelectionDivider:Landroid/graphics/drawable/Drawable;
+Landroid/widget/NumberPicker;->mSelectionDividerHeight:I
Landroid/widget/NumberPicker;->mSelectorWheelPaint:Landroid/graphics/Paint;
Landroid/widget/OverScroller$SplineOverScroller;->mCurrVelocity:F
Landroid/widget/OverScroller;->isScrollingInDirection(FF)Z
@@ -3181,6 +3167,7 @@ Landroid/widget/ScrollView;->mMinimumVelocity:I
Landroid/widget/ScrollView;->mOverflingDistance:I
Landroid/widget/ScrollView;->mOverscrollDistance:I
Landroid/widget/ScrollView;->mScroller:Landroid/widget/OverScroller;
+Landroid/widget/SearchView$SearchAutoComplete;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
Landroid/widget/SearchView;->mCloseButton:Landroid/widget/ImageView;
Landroid/widget/SearchView;->mSearchButton:Landroid/widget/ImageView;
Landroid/widget/SearchView;->mSearchPlate:Landroid/view/View;
@@ -3202,7 +3189,6 @@ Landroid/widget/TabWidget;->setTabSelectionListener(Landroid/widget/TabWidget$On
Landroid/widget/TextView;->assumeLayout()V
Landroid/widget/TextView;->createEditorIfNeeded()V
Landroid/widget/TextView;->getHorizontallyScrolling()Z
-Landroid/widget/TextView;->getTextColor(Landroid/content/Context;Landroid/content/res/TypedArray;I)I
Landroid/widget/TextView;->isSingleLine()Z
Landroid/widget/TextView;->LINES:I
Landroid/widget/TextView;->mCursorDrawableRes:I
@@ -3234,6 +3220,8 @@ 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
+Landroid/widget/ViewAnimator;->mFirstTime:Z
+Landroid/widget/ViewAnimator;->mWhichChild:I
Lcom/android/ims/internal/uce/common/CapInfo;-><init>()V
Lcom/android/ims/internal/uce/common/CapInfo;->setCapTimestamp(J)V
Lcom/android/ims/internal/uce/common/CapInfo;->setCdViaPresenceSupported(Z)V
@@ -3693,6 +3681,7 @@ Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setSoWriteTimeout(I)V
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setUseSessionTickets(Z)V
Lcom/android/org/conscrypt/OpenSSLX509Certificate;->mContext:J
Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;)V
+Lcom/android/org/conscrypt/TrustManagerImpl;->checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
Ldalvik/system/BaseDexClassLoader;->addDexPath(Ljava/lang/String;)V
Ldalvik/system/BaseDexClassLoader;->getLdLibraryPath()Ljava/lang/String;
Ldalvik/system/BaseDexClassLoader;->pathList:Ldalvik/system/DexPathList;
@@ -3937,6 +3926,7 @@ Ljava/util/concurrent/ThreadPoolExecutor;->allowCoreThreadTimeOut:Z
Ljava/util/EnumMap;->keyType:Ljava/lang/Class;
Ljava/util/EnumSet;->elementType:Ljava/lang/Class;
Ljava/util/HashMap$HashIterator;->hasNext()Z
+Ljava/util/HashMap$HashIterator;->remove()V
Ljava/util/HashMap;->modCount:I
Ljava/util/HashMap;->table:[Ljava/util/HashMap$Node;
Ljava/util/HashSet;->map:Ljava/util/HashMap;
diff --git a/config/hiddenapi-vendor-list.txt b/config/hiddenapi-vendor-list.txt
index 4f878ac52b42..fe10f41360a7 100644
--- a/config/hiddenapi-vendor-list.txt
+++ b/config/hiddenapi-vendor-list.txt
@@ -100,11 +100,8 @@ Landroid/content/pm/IPackageManager;->getPackageInfo(Ljava/lang/String;II)Landro
Landroid/content/pm/IPackageStatsObserver;->onGetStatsCompleted(Landroid/content/pm/PackageStats;Z)V
Landroid/database/sqlite/SqliteWrapper;->insert(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/content/ContentValues;)Landroid/net/Uri;
Landroid/database/sqlite/SqliteWrapper;->query(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;
-Landroid/graphics/AvoidXfermode;-><init>(IILandroid/graphics/AvoidXfermode$Mode;)V
Landroid/graphics/Bitmap;->createGraphicBufferHandle()Landroid/graphics/GraphicBuffer;
Landroid/graphics/Bitmap;->createHardwareBitmap(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap;
-Landroid/graphics/Canvas;->clipRegion(Landroid/graphics/Region;)Z
-Landroid/graphics/Canvas;->clipRegion(Landroid/graphics/Region;Landroid/graphics/Region$Op;)Z
Landroid/graphics/drawable/Drawable;->isProjected()Z
Landroid/graphics/drawable/Drawable;->updateTintFilter(Landroid/graphics/PorterDuffColorFilter;Landroid/content/res/ColorStateList;Landroid/graphics/PorterDuff$Mode;)Landroid/graphics/PorterDuffColorFilter;
Landroid/hardware/camera2/CaptureRequest$Key;-><init>(Ljava/lang/String;Ljava/lang/Class;)V
@@ -152,8 +149,6 @@ Landroid/net/ConnectivityManager$PacketKeepaliveCallback;->onStopped()V
Landroid/net/ConnectivityManager;->getActiveNetworkQuotaInfo()Landroid/net/NetworkQuotaInfo;
Landroid/net/ConnectivityManager;->setAirplaneMode(Z)V
Landroid/net/ConnectivityManager;->startNattKeepalive(Landroid/net/Network;ILandroid/net/ConnectivityManager$PacketKeepaliveCallback;Ljava/net/InetAddress;ILjava/net/InetAddress;)Landroid/net/ConnectivityManager$PacketKeepalive;
-Landroid/net/ConnectivityManager;->startUsingNetworkFeature(ILjava/lang/String;)I
-Landroid/net/ConnectivityManager;->stopUsingNetworkFeature(ILjava/lang/String;)I
Landroid/net/ConnectivityManager;->tether(Ljava/lang/String;)I
Landroid/net/ConnectivityManager;->untether(Ljava/lang/String;)I
Landroid/net/DhcpResults;-><init>()V
@@ -355,8 +350,6 @@ Landroid/os/Message;->setCallback(Ljava/lang/Runnable;)Landroid/os/Message;
Landroid/os/Parcel;->readBlob()[B
Landroid/os/Parcel;->readStringArray()[Ljava/lang/String;
Landroid/os/Parcel;->writeBlob([B)V
-Landroid/os/PowerManager;->goToSleep(J)V
-Landroid/os/PowerManager;->isScreenBrightnessBoosted()Z
Landroid/os/Registrant;-><init>(Landroid/os/Handler;ILjava/lang/Object;)V
Landroid/os/Registrant;->clear()V
Landroid/os/Registrant;->notifyRegistrant()V
@@ -514,12 +507,6 @@ Landroid/telephony/TelephonyManager;->nvResetConfig(I)Z
Landroid/telephony/TelephonyManager;->putIntAtIndex(Landroid/content/ContentResolver;Ljava/lang/String;II)Z
Landroid/telephony/TelephonyManager;->setPreferredNetworkType(II)Z
Landroid/text/TextUtils;->isPrintableAsciiOnly(Ljava/lang/CharSequence;)Z
-Landroid/util/FloatMath;->ceil(F)F
-Landroid/util/FloatMath;->cos(F)F
-Landroid/util/FloatMath;->exp(F)F
-Landroid/util/FloatMath;->floor(F)F
-Landroid/util/FloatMath;->sin(F)F
-Landroid/util/FloatMath;->sqrt(F)F
Landroid/util/IconDrawableFactory;->getBadgedIcon(Landroid/content/pm/PackageItemInfo;Landroid/content/pm/ApplicationInfo;I)Landroid/graphics/drawable/Drawable;
Landroid/util/IconDrawableFactory;->newInstance(Landroid/content/Context;)Landroid/util/IconDrawableFactory;
Landroid/util/LocalLog$ReadOnlyLocalLog;->dump(Ljava/io/FileDescriptor;Ljava/io/PrintWriter;[Ljava/lang/String;)V
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 97c9fa58622f..7338bfea9d4d 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -236,6 +236,17 @@ public abstract class ActivityManagerInternal {
int userId, Intent[] intents, Bundle bOptions);
/**
+ * Start activity {@code intent} without calling user-id check.
+ *
+ * - DO NOT call it with the calling UID cleared.
+ * - The caller must do the calling user ID check.
+ *
+ * @return error codes used by {@link IActivityManager#startActivity} and its siblings.
+ */
+ public abstract int startActivityAsUser(IApplicationThread caller, String callingPackage,
+ Intent intent, @Nullable Bundle options, int userId);
+
+ /**
* Get the procstate for the UID. The return value will be between
* {@link ActivityManager#MIN_PROCESS_STATE} and {@link ActivityManager#MAX_PROCESS_STATE}.
* Note if the UID doesn't exist, it'll return {@link ActivityManager#PROCESS_STATE_NONEXISTENT}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5947c51fc930..617d756ff20e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5512,6 +5512,7 @@ public final class ActivityThread extends ClientTransactionHandler {
Process.setArgV0(data.processName);
android.ddm.DdmHandleAppName.setAppName(data.processName,
UserHandle.myUserId());
+ VMRuntime.setProcessPackageName(data.appInfo.packageName);
if (mProfiler.profileFd != null) {
mProfiler.startProfiling();
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index dcf4eec80e69..796e406ce56f 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -110,6 +110,27 @@ public class AppOpsManager {
public static final int MODE_DEFAULT = 3;
/**
+ * Special mode that means "allow only when app is in foreground." This is <b>not</b>
+ * returned from {@link #checkOp}, {@link #noteOp}, {@link #startOp}; rather, when this
+ * mode is set, these functions will return {@link #MODE_ALLOWED} when the app being
+ * checked is currently in the foreground, otherwise {@link #MODE_IGNORED}.
+ * @hide
+ */
+ public static final int MODE_FOREGROUND = 4;
+
+
+ /**
+ * @hide
+ */
+ public static final String[] MODE_NAMES = new String[] {
+ "allow", // MODE_ALLOWED
+ "ignore", // MODE_IGNORED
+ "deny", // MODE_ERRORED
+ "default", // MODE_DEFAULT
+ "foreground", // MODE_FOREGROUND
+ };
+
+ /**
* Metrics about an op when its uid is persistent.
* @hide
*/
@@ -619,83 +640,83 @@ public class AppOpsManager {
* make them all controlled by the same single operation.
*/
private static int[] sOpToSwitch = new int[] {
- OP_COARSE_LOCATION,
- OP_COARSE_LOCATION,
- OP_COARSE_LOCATION,
- OP_VIBRATE,
- OP_READ_CONTACTS,
- OP_WRITE_CONTACTS,
- OP_READ_CALL_LOG,
- OP_WRITE_CALL_LOG,
- OP_READ_CALENDAR,
- OP_WRITE_CALENDAR,
- OP_COARSE_LOCATION,
- OP_POST_NOTIFICATION,
- OP_COARSE_LOCATION,
- OP_CALL_PHONE,
- OP_READ_SMS,
- OP_WRITE_SMS,
- OP_RECEIVE_SMS,
- OP_RECEIVE_SMS,
- OP_RECEIVE_MMS,
- OP_RECEIVE_WAP_PUSH,
- OP_SEND_SMS,
- OP_READ_SMS,
- OP_WRITE_SMS,
- OP_WRITE_SETTINGS,
- OP_SYSTEM_ALERT_WINDOW,
- OP_ACCESS_NOTIFICATIONS,
- OP_CAMERA,
- OP_RECORD_AUDIO,
- OP_PLAY_AUDIO,
- OP_READ_CLIPBOARD,
- OP_WRITE_CLIPBOARD,
- OP_TAKE_MEDIA_BUTTONS,
- OP_TAKE_AUDIO_FOCUS,
- OP_AUDIO_MASTER_VOLUME,
- OP_AUDIO_VOICE_VOLUME,
- OP_AUDIO_RING_VOLUME,
- OP_AUDIO_MEDIA_VOLUME,
- OP_AUDIO_ALARM_VOLUME,
- OP_AUDIO_NOTIFICATION_VOLUME,
- OP_AUDIO_BLUETOOTH_VOLUME,
- OP_WAKE_LOCK,
- OP_COARSE_LOCATION,
- OP_COARSE_LOCATION,
- OP_GET_USAGE_STATS,
- OP_MUTE_MICROPHONE,
- OP_TOAST_WINDOW,
- OP_PROJECT_MEDIA,
- OP_ACTIVATE_VPN,
- OP_WRITE_WALLPAPER,
- OP_ASSIST_STRUCTURE,
- OP_ASSIST_SCREENSHOT,
- OP_READ_PHONE_STATE,
- OP_ADD_VOICEMAIL,
- OP_USE_SIP,
- OP_PROCESS_OUTGOING_CALLS,
- OP_USE_FINGERPRINT,
- OP_BODY_SENSORS,
- OP_READ_CELL_BROADCASTS,
- OP_MOCK_LOCATION,
- OP_READ_EXTERNAL_STORAGE,
- OP_WRITE_EXTERNAL_STORAGE,
- OP_TURN_SCREEN_ON,
- OP_GET_ACCOUNTS,
- OP_RUN_IN_BACKGROUND,
- OP_AUDIO_ACCESSIBILITY_VOLUME,
- OP_READ_PHONE_NUMBERS,
- OP_REQUEST_INSTALL_PACKAGES,
- OP_PICTURE_IN_PICTURE,
- OP_INSTANT_APP_START_FOREGROUND,
- OP_ANSWER_PHONE_CALLS,
- OP_RUN_ANY_IN_BACKGROUND,
- OP_CHANGE_WIFI_STATE,
- OP_REQUEST_DELETE_PACKAGES,
- OP_BIND_ACCESSIBILITY_SERVICE,
- OP_ACCEPT_HANDOVER,
- OP_MANAGE_IPSEC_TUNNELS,
- OP_START_FOREGROUND,
+ OP_COARSE_LOCATION, // COARSE_LOCATION
+ OP_COARSE_LOCATION, // FINE_LOCATION
+ OP_COARSE_LOCATION, // GPS
+ OP_VIBRATE, // VIBRATE
+ OP_READ_CONTACTS, // READ_CONTACTS
+ OP_WRITE_CONTACTS, // WRITE_CONTACTS
+ OP_READ_CALL_LOG, // READ_CALL_LOG
+ OP_WRITE_CALL_LOG, // WRITE_CALL_LOG
+ OP_READ_CALENDAR, // READ_CALENDAR
+ OP_WRITE_CALENDAR, // WRITE_CALENDAR
+ OP_COARSE_LOCATION, // WIFI_SCAN
+ OP_POST_NOTIFICATION, // POST_NOTIFICATION
+ OP_COARSE_LOCATION, // NEIGHBORING_CELLS
+ OP_CALL_PHONE, // CALL_PHONE
+ OP_READ_SMS, // READ_SMS
+ OP_WRITE_SMS, // WRITE_SMS
+ OP_RECEIVE_SMS, // RECEIVE_SMS
+ OP_RECEIVE_SMS, // RECEIVE_EMERGECY_SMS
+ OP_RECEIVE_MMS, // RECEIVE_MMS
+ OP_RECEIVE_WAP_PUSH, // RECEIVE_WAP_PUSH
+ OP_SEND_SMS, // SEND_SMS
+ OP_READ_SMS, // READ_ICC_SMS
+ OP_WRITE_SMS, // WRITE_ICC_SMS
+ OP_WRITE_SETTINGS, // WRITE_SETTINGS
+ OP_SYSTEM_ALERT_WINDOW, // SYSTEM_ALERT_WINDOW
+ OP_ACCESS_NOTIFICATIONS, // ACCESS_NOTIFICATIONS
+ OP_CAMERA, // CAMERA
+ OP_RECORD_AUDIO, // RECORD_AUDIO
+ OP_PLAY_AUDIO, // PLAY_AUDIO
+ OP_READ_CLIPBOARD, // READ_CLIPBOARD
+ OP_WRITE_CLIPBOARD, // WRITE_CLIPBOARD
+ OP_TAKE_MEDIA_BUTTONS, // TAKE_MEDIA_BUTTONS
+ OP_TAKE_AUDIO_FOCUS, // TAKE_AUDIO_FOCUS
+ OP_AUDIO_MASTER_VOLUME, // AUDIO_MASTER_VOLUME
+ OP_AUDIO_VOICE_VOLUME, // AUDIO_VOICE_VOLUME
+ OP_AUDIO_RING_VOLUME, // AUDIO_RING_VOLUME
+ OP_AUDIO_MEDIA_VOLUME, // AUDIO_MEDIA_VOLUME
+ OP_AUDIO_ALARM_VOLUME, // AUDIO_ALARM_VOLUME
+ OP_AUDIO_NOTIFICATION_VOLUME, // AUDIO_NOTIFICATION_VOLUME
+ OP_AUDIO_BLUETOOTH_VOLUME, // AUDIO_BLUETOOTH_VOLUME
+ OP_WAKE_LOCK, // WAKE_LOCK
+ OP_COARSE_LOCATION, // MONITOR_LOCATION
+ OP_COARSE_LOCATION, // MONITOR_HIGH_POWER_LOCATION
+ OP_GET_USAGE_STATS, // GET_USAGE_STATS
+ OP_MUTE_MICROPHONE, // MUTE_MICROPHONE
+ OP_TOAST_WINDOW, // TOAST_WINDOW
+ OP_PROJECT_MEDIA, // PROJECT_MEDIA
+ OP_ACTIVATE_VPN, // ACTIVATE_VPN
+ OP_WRITE_WALLPAPER, // WRITE_WALLPAPER
+ OP_ASSIST_STRUCTURE, // ASSIST_STRUCTURE
+ OP_ASSIST_SCREENSHOT, // ASSIST_SCREENSHOT
+ OP_READ_PHONE_STATE, // READ_PHONE_STATE
+ OP_ADD_VOICEMAIL, // ADD_VOICEMAIL
+ OP_USE_SIP, // USE_SIP
+ OP_PROCESS_OUTGOING_CALLS, // PROCESS_OUTGOING_CALLS
+ OP_USE_FINGERPRINT, // USE_FINGERPRINT
+ OP_BODY_SENSORS, // BODY_SENSORS
+ OP_READ_CELL_BROADCASTS, // READ_CELL_BROADCASTS
+ OP_MOCK_LOCATION, // MOCK_LOCATION
+ OP_READ_EXTERNAL_STORAGE, // READ_EXTERNAL_STORAGE
+ OP_WRITE_EXTERNAL_STORAGE, // WRITE_EXTERNAL_STORAGE
+ OP_TURN_SCREEN_ON, // TURN_SCREEN_ON
+ OP_GET_ACCOUNTS, // GET_ACCOUNTS
+ OP_RUN_IN_BACKGROUND, // RUN_IN_BACKGROUND
+ OP_AUDIO_ACCESSIBILITY_VOLUME, // AUDIO_ACCESSIBILITY_VOLUME
+ OP_READ_PHONE_NUMBERS, // READ_PHONE_NUMBERS
+ OP_REQUEST_INSTALL_PACKAGES, // REQUEST_INSTALL_PACKAGES
+ OP_PICTURE_IN_PICTURE, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
+ OP_INSTANT_APP_START_FOREGROUND, // INSTANT_APP_START_FOREGROUND
+ OP_ANSWER_PHONE_CALLS, // ANSWER_PHONE_CALLS
+ OP_RUN_ANY_IN_BACKGROUND, // OP_RUN_ANY_IN_BACKGROUND
+ OP_CHANGE_WIFI_STATE, // OP_CHANGE_WIFI_STATE
+ OP_REQUEST_DELETE_PACKAGES, // OP_REQUEST_DELETE_PACKAGES
+ OP_BIND_ACCESSIBILITY_SERVICE, // OP_BIND_ACCESSIBILITY_SERVICE
+ OP_ACCEPT_HANDOVER, // ACCEPT_HANDOVER
+ OP_MANAGE_IPSEC_TUNNELS, // MANAGE_IPSEC_HANDOVERS
+ OP_START_FOREGROUND, // START_FOREGROUND
};
/**
@@ -1420,19 +1441,11 @@ public class AppOpsManager {
* Retrieve the human readable mode.
* @hide
*/
- public static String modeToString(int mode) {
- switch (mode) {
- case MODE_ALLOWED:
- return "allow";
- case MODE_IGNORED:
- return "ignore";
- case MODE_ERRORED:
- return "deny";
- case MODE_DEFAULT:
- return "default";
- default:
- return "mode=" + mode;
+ public static String modeToName(int mode) {
+ if (mode >= 0 && mode < MODE_NAMES.length) {
+ return MODE_NAMES[mode];
}
+ return "mode=" + mode;
}
/**
@@ -1554,30 +1567,42 @@ public class AppOpsManager {
}
public long getTime() {
- long time = 0;
- for (int i = 0; i < _NUM_UID_STATE; i++) {
- if (mTimes[i] > time) {
- time = mTimes[i];
- }
- }
- return time;
+ return maxTime(mTimes, 0, _NUM_UID_STATE);
+ }
+
+ public long getLastAccessTime() {
+ return maxTime(mTimes, 0, _NUM_UID_STATE);
+ }
+
+ public long getLastAccessForegroundTime() {
+ return maxTime(mTimes, UID_STATE_PERSISTENT, UID_STATE_FOREGROUND_SERVICE + 1);
}
- public long getTimeFor(int uidState) {
+ public long getLastAccessBackgroundTime() {
+ return maxTime(mTimes, UID_STATE_FOREGROUND_SERVICE + 1, _NUM_UID_STATE);
+ }
+
+ public long getLastTimeFor(int uidState) {
return mTimes[uidState];
}
public long getRejectTime() {
- long time = 0;
- for (int i = 0; i < _NUM_UID_STATE; i++) {
- if (mRejectTimes[i] > time) {
- time = mRejectTimes[i];
- }
- }
- return time;
+ return maxTime(mRejectTimes, 0, _NUM_UID_STATE);
+ }
+
+ public long getLastRejectTime() {
+ return maxTime(mRejectTimes, 0, _NUM_UID_STATE);
+ }
+
+ public long getLastRejectForegroundTime() {
+ return maxTime(mRejectTimes, UID_STATE_PERSISTENT, UID_STATE_FOREGROUND_SERVICE + 1);
+ }
+
+ public long getLastRejectBackgroundTime() {
+ return maxTime(mRejectTimes, UID_STATE_FOREGROUND_SERVICE + 1, _NUM_UID_STATE);
}
- public long getRejectTimeFor(int uidState) {
+ public long getLastRejectTimeFor(int uidState) {
return mRejectTimes[uidState];
}
@@ -1680,6 +1705,7 @@ public class AppOpsManager {
* @param ops The set of operations you are interested in, or null if you want all of them.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
try {
return mService.getPackagesForOps(ops);
@@ -1696,6 +1722,7 @@ public class AppOpsManager {
* @param ops The set of operations you are interested in, or null if you want all of them.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
try {
return mService.getOpsForPackage(uid, packageName, ops);
@@ -2009,6 +2036,17 @@ public class AppOpsManager {
* used for a quick check to see if an operation has been disabled for the application,
* as an early reject of some work. This does not modify the time stamp or other data
* about the operation.
+ *
+ * <p>Important things this will not do (which you need to ultimate use
+ * {@link #noteOp(String, int, String)} or {@link #startOp(String, int, String)} to cover):</p>
+ * <ul>
+ * <li>Verifying the uid and package are consistent, so callers can't spoof
+ * their identity.</li>
+ * <li>Taking into account the current foreground/background state of the
+ * app; apps whose mode varies by this state will always be reported
+ * as {@link #MODE_ALLOWED}.</li>
+ * </ul>
+ *
* @param op The operation to check. One of the OPSTR_* constants.
* @param uid The user id of the application attempting to perform the operation.
* @param packageName The name of the application attempting to perform the operation.
@@ -2128,6 +2166,17 @@ public class AppOpsManager {
* used for a quick check to see if an operation has been disabled for the application,
* as an early reject of some work. This does not modify the time stamp or other data
* about the operation.
+ *
+ * <p>Important things this will not do (which you need to ultimate use
+ * {@link #noteOp(int, int, String)} or {@link #startOp(int, int, String)} to cover):</p>
+ * <ul>
+ * <li>Verifying the uid and package are consistent, so callers can't spoof
+ * their identity.</li>
+ * <li>Taking into account the current foreground/background state of the
+ * app; apps whose mode varies by this state will always be reported
+ * as {@link #MODE_ALLOWED}.</li>
+ * </ul>
+ *
* @param op The operation to check. One of the OP_* constants.
* @param uid The user id of the application attempting to perform the operation.
* @param packageName The name of the application attempting to perform the operation.
@@ -2445,4 +2494,17 @@ public class AppOpsManager {
public static String[] getOpStrs() {
return Arrays.copyOf(sOpToString, sOpToString.length);
}
+
+ /**
+ * @hide
+ */
+ public static long maxTime(long[] times, int start, int end) {
+ long time = 0;
+ for (int i = start; i < end; i++) {
+ if (times[i] > time) {
+ time = times[i];
+ }
+ }
+ return time;
+ }
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 9a491bc38280..95117862a8da 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1048,6 +1048,22 @@ class ContextImpl extends Context {
}
@Override
+ public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
+ String[] receiverPermissions) {
+ warnIfCallingFromSystemProcess();
+ String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+ try {
+ intent.prepareToLeaveProcess(this);
+ ActivityManager.getService().broadcastIntent(
+ mMainThread.getApplicationThread(), intent, resolvedType, null,
+ Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
+ null, false, false, user.getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index c5b80196cf26..327d4fe7e363 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2722,7 +2722,40 @@ public class Notification implements Parcelable
* @hide
*/
public static boolean areRemoteViewsChanged(Builder first, Builder second) {
- return !first.usesStandardHeader() || !second.usesStandardHeader();
+ if (!Objects.equals(first.usesStandardHeader(), second.usesStandardHeader())) {
+ return true;
+ }
+
+ if (areRemoteViewsChanged(first.mN.contentView, second.mN.contentView)) {
+ return true;
+ }
+ if (areRemoteViewsChanged(first.mN.bigContentView, second.mN.bigContentView)) {
+ return true;
+ }
+ if (areRemoteViewsChanged(first.mN.headsUpContentView, second.mN.headsUpContentView)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private static boolean areRemoteViewsChanged(RemoteViews first, RemoteViews second) {
+ if (first == null && second == null) {
+ return false;
+ }
+ if (first == null && second != null || first != null && second == null) {
+ return true;
+ }
+
+ if (!Objects.equals(first.getLayoutId(), second.getLayoutId())) {
+ return true;
+ }
+
+ if (!Objects.equals(first.getSequenceNumber(), second.getSequenceNumber())) {
+ return true;
+ }
+
+ return false;
}
/**
@@ -5102,6 +5135,10 @@ public class Notification implements Parcelable
savedBundle.getBoolean(EXTRA_SHOW_CHRONOMETER));
publicExtras.putBoolean(EXTRA_CHRONOMETER_COUNT_DOWN,
savedBundle.getBoolean(EXTRA_CHRONOMETER_COUNT_DOWN));
+ String appName = savedBundle.getString(EXTRA_SUBSTITUTE_APP_NAME);
+ if (appName != null) {
+ publicExtras.putString(EXTRA_SUBSTITUTE_APP_NAME, appName);
+ }
mN.extras = publicExtras;
RemoteViews view;
if (ambient) {
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 9e47ced433e3..ba355f9f9c1d 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -76,6 +76,7 @@ public final class NotificationChannel implements Parcelable {
private static final String ATT_CONTENT_TYPE = "content_type";
private static final String ATT_SHOW_BADGE = "show_badge";
private static final String ATT_USER_LOCKED = "locked";
+ private static final String ATT_FG_SERVICE_SHOWN = "fgservice";
private static final String ATT_GROUP = "group";
private static final String ATT_BLOCKABLE_SYSTEM = "blockable_system";
private static final String DELIMITER = ",";
@@ -144,6 +145,7 @@ public final class NotificationChannel implements Parcelable {
// Bitwise representation of fields that have been changed by the user, preventing the app from
// making changes to these fields.
private int mUserLockedFields;
+ private boolean mFgServiceShown;
private boolean mVibrationEnabled;
private boolean mShowBadge = DEFAULT_SHOW_BADGE;
private boolean mDeleted = DEFAULT_DELETED;
@@ -200,6 +202,7 @@ public final class NotificationChannel implements Parcelable {
mLights = in.readByte() != 0;
mVibration = in.createLongArray();
mUserLockedFields = in.readInt();
+ mFgServiceShown = in.readByte() != 0;
mVibrationEnabled = in.readByte() != 0;
mShowBadge = in.readByte() != 0;
mDeleted = in.readByte() != 0;
@@ -245,6 +248,7 @@ public final class NotificationChannel implements Parcelable {
dest.writeByte(mLights ? (byte) 1 : (byte) 0);
dest.writeLongArray(mVibration);
dest.writeInt(mUserLockedFields);
+ dest.writeByte(mFgServiceShown ? (byte) 1 : (byte) 0);
dest.writeByte(mVibrationEnabled ? (byte) 1 : (byte) 0);
dest.writeByte(mShowBadge ? (byte) 1 : (byte) 0);
dest.writeByte(mDeleted ? (byte) 1 : (byte) 0);
@@ -281,6 +285,13 @@ public final class NotificationChannel implements Parcelable {
/**
* @hide
*/
+ public void setFgServiceShown(boolean shown) {
+ mFgServiceShown = shown;
+ }
+
+ /**
+ * @hide
+ */
public void setDeleted(boolean deleted) {
mDeleted = deleted;
}
@@ -576,6 +587,13 @@ public final class NotificationChannel implements Parcelable {
/**
* @hide
*/
+ public boolean isFgServiceShown() {
+ return mFgServiceShown;
+ }
+
+ /**
+ * @hide
+ */
public boolean isBlockableSystem() {
return mBlockableSystem;
}
@@ -620,6 +638,7 @@ public final class NotificationChannel implements Parcelable {
setDeleted(safeBool(parser, ATT_DELETED, false));
setGroup(parser.getAttributeValue(null, ATT_GROUP));
lockFields(safeInt(parser, ATT_USER_LOCKED, 0));
+ setFgServiceShown(safeBool(parser, ATT_FG_SERVICE_SHOWN, false));
setBlockableSystem(safeBool(parser, ATT_BLOCKABLE_SYSTEM, false));
}
@@ -724,6 +743,9 @@ public final class NotificationChannel implements Parcelable {
if (getUserLockedFields() != 0) {
out.attribute(null, ATT_USER_LOCKED, Integer.toString(getUserLockedFields()));
}
+ if (isFgServiceShown()) {
+ out.attribute(null, ATT_FG_SERVICE_SHOWN, Boolean.toString(isFgServiceShown()));
+ }
if (canShowBadge()) {
out.attribute(null, ATT_SHOW_BADGE, Boolean.toString(canShowBadge()));
}
@@ -772,6 +794,7 @@ public final class NotificationChannel implements Parcelable {
record.put(ATT_LIGHT_COLOR, Integer.toString(getLightColor()));
record.put(ATT_VIBRATION_ENABLED, Boolean.toString(shouldVibrate()));
record.put(ATT_USER_LOCKED, Integer.toString(getUserLockedFields()));
+ record.put(ATT_FG_SERVICE_SHOWN, Boolean.toString(isFgServiceShown()));
record.put(ATT_VIBRATION, longArrayToString(getVibrationPattern()));
record.put(ATT_SHOW_BADGE, Boolean.toString(canShowBadge()));
record.put(ATT_DELETED, Boolean.toString(isDeleted()));
@@ -933,6 +956,7 @@ public final class NotificationChannel implements Parcelable {
+ ", mLightColor=" + mLightColor
+ ", mVibration=" + Arrays.toString(mVibration)
+ ", mUserLockedFields=" + Integer.toHexString(mUserLockedFields)
+ + ", mFgServiceShown=" + mFgServiceShown
+ ", mVibrationEnabled=" + mVibrationEnabled
+ ", mShowBadge=" + mShowBadge
+ ", mDeleted=" + mDeleted
@@ -963,6 +987,7 @@ public final class NotificationChannel implements Parcelable {
}
}
proto.write(NotificationChannelProto.USER_LOCKED_FIELDS, mUserLockedFields);
+ proto.write(NotificationChannelProto.FG_SERVICE_SHOWN, mFgServiceShown);
proto.write(NotificationChannelProto.IS_VIBRATION_ENABLED, mVibrationEnabled);
proto.write(NotificationChannelProto.SHOW_BADGE, mShowBadge);
proto.write(NotificationChannelProto.IS_DELETED, mDeleted);
diff --git a/core/java/android/app/slice/SliceMetrics.java b/core/java/android/app/slice/SliceMetrics.java
index 20c1390b25ff..746beaf939d9 100644
--- a/core/java/android/app/slice/SliceMetrics.java
+++ b/core/java/android/app/slice/SliceMetrics.java
@@ -18,9 +18,11 @@ package android.app.slice;
import android.annotation.NonNull;
import android.content.Context;
+import android.metrics.LogMaker;
import android.net.Uri;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
/**
* Metrics interface for slices.
@@ -34,24 +36,38 @@ public class SliceMetrics {
private static final String TAG = "SliceMetrics";
private MetricsLogger mMetricsLogger;
+ private LogMaker mLogMaker;
/**
* An object to be used throughout the life of a slice to register events.
*/
public SliceMetrics(@NonNull Context context, @NonNull Uri uri) {
mMetricsLogger = new MetricsLogger();
+ mLogMaker = new LogMaker(MetricsEvent.VIEW_UNKNOWN);
+ mLogMaker.addTaggedData(MetricsEvent.FIELD_SLICE_AUTHORITY, uri.getAuthority());
+ mLogMaker.addTaggedData(MetricsEvent.FIELD_SLICE_PATH, uri.getPath());
}
/**
* To be called whenever the slice becomes visible to the user.
*/
public void logVisible() {
+ synchronized (mLogMaker) {
+ mLogMaker.setCategory(MetricsEvent.SLICE)
+ .setType(MetricsEvent.TYPE_OPEN);
+ mMetricsLogger.write(mLogMaker);
+ }
}
/**
* To be called whenever the slice becomes invisible to the user.
*/
public void logHidden() {
+ synchronized (mLogMaker) {
+ mLogMaker.setCategory(MetricsEvent.SLICE)
+ .setType(MetricsEvent.TYPE_CLOSE);
+ mMetricsLogger.write(mLogMaker);
+ }
}
/**
@@ -68,5 +84,12 @@ public class SliceMetrics {
* @param subSlice The URI of the sub-slice that is the subject of the interaction.
*/
public void logTouch(int actionType, @NonNull Uri subSlice) {
+ synchronized (mLogMaker) {
+ mLogMaker.setCategory(MetricsEvent.SLICE)
+ .setType(MetricsEvent.TYPE_ACTION)
+ .addTaggedData(MetricsEvent.FIELD_SUBSLICE_AUTHORITY, subSlice.getAuthority())
+ .addTaggedData(MetricsEvent.FIELD_SUBSLICE_PATH, subSlice.getPath());
+ mMetricsLogger.write(mLogMaker);
+ }
}
}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index ac21395c2fa7..7a6b72e980f5 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -848,7 +848,11 @@ public final class BluetoothDevice implements Parcelable {
return null;
}
try {
- return service.getRemoteName(this);
+ String name = service.getRemoteName(this);
+ if (name != null) {
+ return name.replaceAll("[\\t\\n\\r]+", " ");
+ }
+ return null;
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ede7ee4b9a6b..90a94ee76085 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1976,6 +1976,33 @@ public abstract class Context {
/**
* Broadcast the given intent to all interested BroadcastReceivers, allowing
+ * an array of required permissions to be enforced. This call is asynchronous; it returns
+ * immediately, and you will continue executing while the receivers are run. No results are
+ * propagated from receivers and receivers can not abort the broadcast. If you want to allow
+ * receivers to propagate results or abort the broadcast, you must send an ordered broadcast
+ * using {@link #sendOrderedBroadcast(Intent, String)}.
+ *
+ * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
+ *
+ * @param intent The Intent to broadcast; all receivers matching this
+ * Intent will receive the broadcast.
+ * @param user The user to send the broadcast to.
+ * @param receiverPermissions Array of names of permissions that a receiver must hold
+ * in order to receive your broadcast.
+ * If null or empty, no permissions are required.
+ *
+ * @see android.content.BroadcastReceiver
+ * @see #registerReceiver
+ * @see #sendBroadcast(Intent)
+ * @see #sendOrderedBroadcast(Intent, String)
+ * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
+ * @hide
+ */
+ public abstract void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
+ String[] receiverPermissions);
+
+ /**
+ * Broadcast the given intent to all interested BroadcastReceivers, allowing
* an optional required permission to be enforced. This
* call is asynchronous; it returns immediately, and you will continue
* executing while the receivers are run. No results are propagated from
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 1867a6d879c7..bae99b85d6b8 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -456,6 +456,13 @@ public class ContextWrapper extends Context {
}
/** @hide */
+ @Override
+ public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
+ String[] receiverPermissions) {
+ mBase.sendBroadcastAsUserMultiplePermissions(intent, user, receiverPermissions);
+ }
+
+ /** @hide */
@SystemApi
@Override
public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 206ed719a55b..dec2cd42c5f9 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3659,6 +3659,10 @@ public class Intent implements Parcelable, Cloneable {
* <p class="note">This is a protected intent that can only be sent by the system.
* @hide
* @removed
+ * @deprecated Use {@link android.provider.Telephony.ServiceStateTable} and the helper
+ * functions {@code ServiceStateTable.getUriForSubscriptionIdAndField} and
+ * {@code ServiceStateTable.getUriForSubscriptionId} to subscribe to changes to the ServiceState
+ * for a given subscription id and field with a ContentObserver or using JobScheduler.
*/
@Deprecated
@SystemApi
@@ -3674,6 +3678,7 @@ public class Intent implements Parcelable, Cloneable {
* @see android.telephony.ServiceState#STATE_POWER_OFF
* @hide
* @removed
+ * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#VOICE_REG_STATE}.
*/
@Deprecated
@SystemApi
@@ -3687,6 +3692,7 @@ public class Intent implements Parcelable, Cloneable {
* @see android.telephony.ServiceState#STATE_POWER_OFF
* @hide
* @removed
+ * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#DATA_REG_STATE}.
*/
@Deprecated
@SystemApi
@@ -3697,6 +3703,7 @@ public class Intent implements Parcelable, Cloneable {
* type.
* @hide
* @removed
+ * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#VOICE_ROAMING_TYPE}.
*/
@Deprecated
@SystemApi
@@ -3707,6 +3714,7 @@ public class Intent implements Parcelable, Cloneable {
* type.
* @hide
* @removed
+ * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#DATA_ROAMING_TYPE}.
*/
@Deprecated
@SystemApi
@@ -3718,6 +3726,8 @@ public class Intent implements Parcelable, Cloneable {
* {@code null} if the operator name is not known or unregistered.
* @hide
* @removed
+ * @deprecated Use
+ * {@link android.provider.Telephony.ServiceStateTable#VOICE_OPERATOR_ALPHA_LONG}.
*/
@Deprecated
@SystemApi
@@ -3729,6 +3739,8 @@ public class Intent implements Parcelable, Cloneable {
* {@code null} if the operator name is not known or unregistered.
* @hide
* @removed
+ * @deprecated Use
+ * {@link android.provider.Telephony.ServiceStateTable#VOICE_OPERATOR_ALPHA_SHORT}.
*/
@Deprecated
@SystemApi
@@ -3740,6 +3752,7 @@ public class Intent implements Parcelable, Cloneable {
* network.
* @hide
* @removed
+ * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#VOICE_OPERATOR_NUMERIC}.
*/
@Deprecated
@SystemApi
@@ -3751,6 +3764,8 @@ public class Intent implements Parcelable, Cloneable {
* {@code null} if the operator name is not known or unregistered.
* @hide
* @removed
+ * @deprecated Use
+ * {@link android.provider.Telephony.ServiceStateTable#DATA_OPERATOR_ALPHA_LONG}.
*/
@Deprecated
@SystemApi
@@ -3762,6 +3777,8 @@ public class Intent implements Parcelable, Cloneable {
* {@code null} if the operator name is not known or unregistered.
* @hide
* @removed
+ * @deprecated Use
+ * {@link android.provider.Telephony.ServiceStateTable#DATA_OPERATOR_ALPHA_SHORT}.
*/
@Deprecated
@SystemApi
@@ -3773,6 +3790,7 @@ public class Intent implements Parcelable, Cloneable {
* data operator.
* @hide
* @removed
+ * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#DATA_OPERATOR_NUMERIC}.
*/
@Deprecated
@SystemApi
@@ -3784,6 +3802,8 @@ public class Intent implements Parcelable, Cloneable {
* Will be {@code true} if manual mode, {@code false} if automatic mode.
* @hide
* @removed
+ * @deprecated Use
+ * {@link android.provider.Telephony.ServiceStateTable#IS_MANUAL_NETWORK_SELECTION}.
*/
@Deprecated
@SystemApi
@@ -3794,6 +3814,8 @@ public class Intent implements Parcelable, Cloneable {
* radio technology.
* @hide
* @removed
+ * @deprecated Use
+ * {@link android.provider.Telephony.ServiceStateTable#RIL_VOICE_RADIO_TECHNOLOGY}.
*/
@Deprecated
@SystemApi
@@ -3804,6 +3826,8 @@ public class Intent implements Parcelable, Cloneable {
* radio technology.
* @hide
* @removed
+ * @deprecated Use
+ * {@link android.provider.Telephony.ServiceStateTable#RIL_DATA_RADIO_TECHNOLOGY}.
*/
@Deprecated
@SystemApi
@@ -3815,6 +3839,7 @@ public class Intent implements Parcelable, Cloneable {
* Will be {@code true} if support, {@code false} otherwise.
* @hide
* @removed
+ * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#CSS_INDICATOR}.
*/
@Deprecated
@SystemApi
@@ -3825,6 +3850,7 @@ public class Intent implements Parcelable, Cloneable {
* id. {@code Integer.MAX_VALUE} if unknown.
* @hide
* @removed
+ * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#NETWORK_ID}.
*/
@Deprecated
@SystemApi
@@ -3835,6 +3861,7 @@ public class Intent implements Parcelable, Cloneable {
* {@code Integer.MAX_VALUE} if unknown.
* @hide
* @removed
+ * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#SYSTEM_ID}.
*/
@Deprecated
@SystemApi
@@ -3845,6 +3872,7 @@ public class Intent implements Parcelable, Cloneable {
* indicator if registered on a CDMA or EVDO system or {@code -1} if not.
* @hide
* @removed
+ * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#CDMA_ROAMING_INDICATOR}.
*/
@Deprecated
@SystemApi
@@ -3855,6 +3883,8 @@ public class Intent implements Parcelable, Cloneable {
* indicator from the PRL if registered on a CDMA or EVDO system {@code -1} if not.
* @hide
* @removed
+ * @deprecated Use
+ * {@link android.provider.Telephony.ServiceStateTable#CDMA_DEFAULT_ROAMING_INDICATOR}.
*/
@Deprecated
@SystemApi
@@ -3866,6 +3896,7 @@ public class Intent implements Parcelable, Cloneable {
* {@code true} if in emergency only mode, {@code false} otherwise.
* @hide
* @removed
+ * @deprecated Use {@link android.provider.Telephony.ServiceStateTable#IS_EMERGENCY_ONLY}.
*/
@Deprecated
@SystemApi
@@ -3877,6 +3908,8 @@ public class Intent implements Parcelable, Cloneable {
* {@code true} if registration indicates roaming, {@code false} otherwise
* @hide
* @removed
+ * @deprecated Use
+ * {@link android.provider.Telephony.ServiceStateTable#IS_DATA_ROAMING_FROM_REGISTRATION}.
*/
@Deprecated
@SystemApi
@@ -3889,6 +3922,8 @@ public class Intent implements Parcelable, Cloneable {
* {@code true} if carrier aggregation is in use, {@code false} otherwise.
* @hide
* @removed
+ * @deprecated Use
+ * {@link android.provider.Telephony.ServiceStateTable#IS_USING_CARRIER_AGGREGATION}.
*/
@Deprecated
@SystemApi
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index ae1c2071eeca..ba7710b8ef48 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -16,6 +16,7 @@
package android.content.pm;
+import android.app.IApplicationThread;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentSender;
@@ -42,10 +43,10 @@ interface ILauncherApps {
String callingPackage, String packageName, in UserHandle user);
ActivityInfo resolveActivity(
String callingPackage, in ComponentName component, in UserHandle user);
- void startActivityAsUser(String callingPackage,
+ void startActivityAsUser(in IApplicationThread caller, String callingPackage,
in ComponentName component, in Rect sourceBounds,
in Bundle opts, in UserHandle user);
- void showAppDetailsAsUser(
+ void showAppDetailsAsUser(in IApplicationThread caller,
String callingPackage, in ComponentName component, in Rect sourceBounds,
in Bundle opts, in UserHandle user);
boolean isPackageEnabled(String callingPackage, String packageName, in UserHandle user);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 8717601cfde0..fa423e29406a 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -548,7 +548,8 @@ public class LauncherApps {
Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier());
}
try {
- mService.startActivityAsUser(mContext.getPackageName(),
+ mService.startActivityAsUser(mContext.getIApplicationThread(),
+ mContext.getPackageName(),
component, sourceBounds, opts, user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
@@ -568,7 +569,8 @@ public class LauncherApps {
Rect sourceBounds, Bundle opts) {
logErrorForInvalidProfileAccess(user);
try {
- mService.showAppDetailsAsUser(mContext.getPackageName(),
+ mService.showAppDetailsAsUser(mContext.getIApplicationThread(),
+ mContext.getPackageName(),
component, sourceBounds, opts, user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 19b5c45f3a81..193e56ef404d 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1905,6 +1905,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* Return whether the screen has a wide color gamut and wide color gamut rendering
* is supported by this device.
*
+ * When true, it implies the screen is colorspace aware but not
+ * necessarily color-managed. The final colors may still be changed by the
+ * screen depending on user settings.
+ *
* @return true if the screen has a wide color gamut and wide color gamut rendering
* is supported, false otherwise
*/
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index c58cde006759..7adea6a880be 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -128,6 +128,14 @@ public class Resources {
private final ArrayList<WeakReference<Theme>> mThemeRefs = new ArrayList<>();
/**
+ * To avoid leaking WeakReferences to garbage collected Themes on the
+ * mThemeRefs list, we flush the list of stale references any time the
+ * mThemeRefNextFlushSize is reached.
+ */
+ private static final int MIN_THEME_REFS_FLUSH_SIZE = 32;
+ private int mThemeRefsNextFlushSize = MIN_THEME_REFS_FLUSH_SIZE;
+
+ /**
* Returns the most appropriate default theme for the specified target SDK version.
* <ul>
* <li>Below API 11: Gingerbread
@@ -1770,6 +1778,13 @@ public class Resources {
theme.setImpl(mResourcesImpl.newThemeImpl());
synchronized (mThemeRefs) {
mThemeRefs.add(new WeakReference<>(theme));
+
+ // Clean up references to garbage collected themes
+ if (mThemeRefs.size() > mThemeRefsNextFlushSize) {
+ mThemeRefs.removeIf(ref -> ref.get() == null);
+ mThemeRefsNextFlushSize = Math.max(MIN_THEME_REFS_FLUSH_SIZE,
+ 2 * mThemeRefs.size());
+ }
}
return theme;
}
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 9a276fbd1ec0..1b80d3d5ee57 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -18,19 +18,23 @@ package android.hardware;
import static android.system.OsConstants.*;
+import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.ActivityThread;
+import android.app.AppOpsManager;
import android.content.Context;
import android.graphics.ImageFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
+import android.media.AudioAttributes;
import android.media.IAudioService;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.renderscript.Allocation;
@@ -43,6 +47,10 @@ import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.app.IAppOpsService;
+
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -174,6 +182,15 @@ public class Camera {
private boolean mFaceDetectionRunning = false;
private final Object mAutoFocusCallbackLock = new Object();
+ private final Object mShutterSoundLock = new Object();
+ // for AppOps
+ private @Nullable IAppOpsService mAppOps;
+ private IAppOpsCallback mAppOpsCallback;
+ @GuardedBy("mShutterSoundLock")
+ private boolean mHasAppOpsPlayAudio = true;
+ @GuardedBy("mShutterSoundLock")
+ private boolean mShutterSoundEnabledFromApp = true;
+
private static final int NO_ERROR = 0;
/**
@@ -526,6 +543,7 @@ public class Camera {
// Should never hit this.
throw new RuntimeException("Unknown camera error");
}
+ initAppOps();
}
@@ -547,6 +565,33 @@ public class Camera {
* An empty Camera for testing purpose.
*/
Camera() {
+ initAppOps();
+ }
+
+ private void initAppOps() {
+ IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
+ mAppOps = IAppOpsService.Stub.asInterface(b);
+ // initialize mHasAppOpsPlayAudio
+ updateAppOpsPlayAudio();
+ // register a callback to monitor whether the OP_PLAY_AUDIO is still allowed
+ mAppOpsCallback = new IAppOpsCallbackWrapper(this);
+ try {
+ mAppOps.startWatchingMode(AppOpsManager.OP_PLAY_AUDIO,
+ ActivityThread.currentPackageName(), mAppOpsCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error registering appOps callback", e);
+ mHasAppOpsPlayAudio = false;
+ }
+ }
+
+ private void releaseAppOps() {
+ try {
+ if (mAppOps != null) {
+ mAppOps.stopWatchingMode(mAppOpsCallback);
+ }
+ } catch (Exception e) {
+ // nothing to do here, the object is supposed to be released anyway
+ }
}
@Override
@@ -568,6 +613,7 @@ public class Camera {
public final void release() {
native_release();
mFaceDetectionRunning = false;
+ releaseAppOps();
}
/**
@@ -1623,7 +1669,17 @@ public class Camera {
Log.e(TAG, "Audio service is unavailable for queries");
}
}
- return _enableShutterSound(enabled);
+ synchronized (mShutterSoundLock) {
+ if (enabled && mHasAppOpsPlayAudio) {
+ Log.i(TAG, "Shutter sound is not allowed by AppOpsManager");
+ return false;
+ }
+ boolean ret = _enableShutterSound(enabled);
+ if (ret) {
+ mShutterSoundEnabledFromApp = enabled;
+ }
+ return ret;
+ }
}
/**
@@ -1648,6 +1704,49 @@ public class Camera {
private native final boolean _enableShutterSound(boolean enabled);
+ private static class IAppOpsCallbackWrapper extends IAppOpsCallback.Stub {
+ private final WeakReference<Camera> mWeakCamera;
+
+ IAppOpsCallbackWrapper(Camera camera) {
+ mWeakCamera = new WeakReference<Camera>(camera);
+ }
+
+ @Override
+ public void opChanged(int op, int uid, String packageName) {
+ if (op == AppOpsManager.OP_PLAY_AUDIO) {
+ final Camera camera = mWeakCamera.get();
+ if (camera != null) {
+ camera.updateAppOpsPlayAudio();
+ }
+ }
+ }
+ }
+
+ private void updateAppOpsPlayAudio() {
+ synchronized (mShutterSoundLock) {
+ boolean oldHasAppOpsPlayAudio = mHasAppOpsPlayAudio;
+ try {
+ int mode = AppOpsManager.MODE_IGNORED;
+ if (mAppOps != null) {
+ mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO,
+ AudioAttributes.USAGE_ASSISTANCE_SONIFICATION,
+ Process.myUid(), ActivityThread.currentPackageName());
+ }
+ mHasAppOpsPlayAudio = mode == AppOpsManager.MODE_ALLOWED;
+ } catch (RemoteException e) {
+ Log.e(TAG, "AppOpsService check audio operation failed");
+ mHasAppOpsPlayAudio = false;
+ }
+ if (oldHasAppOpsPlayAudio != mHasAppOpsPlayAudio) {
+ if (!mHasAppOpsPlayAudio) {
+ _enableShutterSound(false);
+ } else {
+ _enableShutterSound(mShutterSoundEnabledFromApp);
+ }
+ }
+ }
+ }
+
/**
* Callback interface for zoom changes during a smooth zoom operation.
*
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 03221d455edb..ebbfe1c26a9c 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -45,7 +45,6 @@ import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.util.Log;
import android.util.Slog;
import java.security.Signature;
@@ -417,7 +416,7 @@ public class FingerprintManager implements BiometricFingerprintConstants {
if (cancel != null) {
if (cancel.isCanceled()) {
- Log.w(TAG, "authentication already canceled");
+ Slog.w(TAG, "authentication already canceled");
return;
} else {
cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
@@ -432,7 +431,7 @@ public class FingerprintManager implements BiometricFingerprintConstants {
mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags,
mContext.getOpPackageName(), null /* bundle */, null /* receiver */);
} catch (RemoteException e) {
- Log.w(TAG, "Remote exception while authenticating: ", e);
+ Slog.w(TAG, "Remote exception while authenticating: ", e);
if (callback != null) {
// Though this may not be a hardware issue, it will cause apps to give up or try
// again later.
@@ -456,7 +455,7 @@ public class FingerprintManager implements BiometricFingerprintConstants {
@NonNull BiometricAuthenticator.AuthenticationCallback callback) {
mCryptoObject = crypto;
if (cancel.isCanceled()) {
- Log.w(TAG, "authentication already canceled");
+ Slog.w(TAG, "authentication already canceled");
return;
} else {
cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
@@ -470,7 +469,7 @@ public class FingerprintManager implements BiometricFingerprintConstants {
mService.authenticate(mToken, sessionId, userId, mServiceReceiver,
0 /* flags */, mContext.getOpPackageName(), bundle, receiver);
} catch (RemoteException e) {
- Log.w(TAG, "Remote exception while authenticating", e);
+ Slog.w(TAG, "Remote exception while authenticating", e);
mExecutor.execute(() -> {
callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
@@ -576,7 +575,7 @@ public class FingerprintManager implements BiometricFingerprintConstants {
if (cancel != null) {
if (cancel.isCanceled()) {
- Log.w(TAG, "enrollment already canceled");
+ Slog.w(TAG, "enrollment already canceled");
return;
} else {
cancel.setOnCancelListener(new OnEnrollCancelListener());
@@ -588,7 +587,7 @@ public class FingerprintManager implements BiometricFingerprintConstants {
mService.enroll(mToken, token, userId, mServiceReceiver, flags,
mContext.getOpPackageName());
} catch (RemoteException e) {
- Log.w(TAG, "Remote exception in enroll: ", e);
+ Slog.w(TAG, "Remote exception in enroll: ", e);
if (callback != null) {
// Though this may not be a hardware issue, it will cause apps to give up or try
// again later.
@@ -660,7 +659,7 @@ public class FingerprintManager implements BiometricFingerprintConstants {
mRemovalFingerprint = fp;
mService.remove(mToken, fp.getFingerId(), fp.getGroupId(), userId, mServiceReceiver);
} catch (RemoteException e) {
- Log.w(TAG, "Remote exception in remove: ", e);
+ Slog.w(TAG, "Remote exception in remove: ", e);
if (callback != null) {
callback.onRemovalError(fp, FINGERPRINT_ERROR_HW_UNAVAILABLE,
getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
@@ -682,7 +681,7 @@ public class FingerprintManager implements BiometricFingerprintConstants {
mEnumerateCallback = callback;
mService.enumerate(mToken, userId, mServiceReceiver);
} catch (RemoteException e) {
- Log.w(TAG, "Remote exception in enumerate: ", e);
+ Slog.w(TAG, "Remote exception in enumerate: ", e);
if (callback != null) {
callback.onEnumerateError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
@@ -708,7 +707,7 @@ public class FingerprintManager implements BiometricFingerprintConstants {
throw e.rethrowFromSystemServer();
}
} else {
- Log.w(TAG, "rename(): Service not connected!");
+ Slog.w(TAG, "rename(): Service not connected!");
}
}
@@ -791,7 +790,7 @@ public class FingerprintManager implements BiometricFingerprintConstants {
throw e.rethrowFromSystemServer();
}
} else {
- Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
+ Slog.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
}
return false;
}
@@ -810,7 +809,7 @@ public class FingerprintManager implements BiometricFingerprintConstants {
throw e.rethrowFromSystemServer();
}
} else {
- Log.w(TAG, "getAuthenticatorId(): Service not connected!");
+ Slog.w(TAG, "getAuthenticatorId(): Service not connected!");
}
return 0;
}
@@ -830,7 +829,7 @@ public class FingerprintManager implements BiometricFingerprintConstants {
throw e.rethrowFromSystemServer();
}
} else {
- Log.w(TAG, "resetTimeout(): Service not connected!");
+ Slog.w(TAG, "resetTimeout(): Service not connected!");
}
}
@@ -867,7 +866,7 @@ public class FingerprintManager implements BiometricFingerprintConstants {
throw e.rethrowFromSystemServer();
}
} else {
- Log.w(TAG, "addLockoutResetCallback(): Service not connected!");
+ Slog.w(TAG, "addLockoutResetCallback(): Service not connected!");
}
}
@@ -915,20 +914,20 @@ public class FingerprintManager implements BiometricFingerprintConstants {
return;
}
if (fingerprint == null) {
- Log.e(TAG, "Received MSG_REMOVED, but fingerprint is null");
+ Slog.e(TAG, "Received MSG_REMOVED, but fingerprint is null");
return;
}
int fingerId = fingerprint.getFingerId();
int reqFingerId = mRemovalFingerprint.getFingerId();
if (reqFingerId != 0 && fingerId != 0 && fingerId != reqFingerId) {
- Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
+ Slog.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
return;
}
int groupId = fingerprint.getGroupId();
int reqGroupId = mRemovalFingerprint.getGroupId();
if (groupId != reqGroupId) {
- Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
+ Slog.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
return;
}
diff --git a/core/java/android/hardware/radio/RadioMetadata.java b/core/java/android/hardware/radio/RadioMetadata.java
index 6e510607754a..baa7a502688e 100644
--- a/core/java/android/hardware/radio/RadioMetadata.java
+++ b/core/java/android/hardware/radio/RadioMetadata.java
@@ -269,6 +269,29 @@ public final class RadioMetadata implements Parcelable {
mBundle = in.readBundle();
}
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("RadioMetadata[");
+
+ final String removePrefix = "android.hardware.radio.metadata";
+
+ boolean first = true;
+ for (String key : mBundle.keySet()) {
+ if (first) first = false;
+ else sb.append(", ");
+
+ String keyDisp = key;
+ if (key.startsWith(removePrefix)) keyDisp = key.substring(removePrefix.length());
+
+ sb.append(keyDisp);
+ sb.append('=');
+ sb.append(mBundle.get(key));
+ }
+
+ sb.append("]");
+ return sb.toString();
+ }
+
/**
* Returns {@code true} if the given key is contained in the meta data
*
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index 848c59610720..f17e0f026fda 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -77,10 +77,18 @@ public final class Looper {
private Printer mLogging;
private long mTraceTag;
- /* If set, the looper will show a warning log if a message dispatch takes longer than time. */
+ /**
+ * If set, the looper will show a warning log if a message dispatch takes longer than this.
+ */
private long mSlowDispatchThresholdMs;
- /** Initialize the current thread as a looper.
+ /**
+ * If set, the looper will show a warning log if a message delivery (actual delivery time -
+ * post time) takes longer than this.
+ */
+ private long mSlowDeliveryThresholdMs;
+
+ /** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
@@ -138,6 +146,16 @@ public final class Looper {
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
+ // Allow overriding a threshold with a system prop. e.g.
+ // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
+ final int thresholdOverride =
+ SystemProperties.getInt("log.looper."
+ + Process.myUid() + "."
+ + Thread.currentThread().getName()
+ + ".slow", 0);
+
+ boolean slowDeliveryDetected = false;
+
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
@@ -152,30 +170,50 @@ public final class Looper {
msg.callback + ": " + msg.what);
}
- final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
-
final long traceTag = me.mTraceTag;
+ long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
+ long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
+ if (thresholdOverride > 0) {
+ slowDispatchThresholdMs = thresholdOverride;
+ slowDeliveryThresholdMs = thresholdOverride;
+ }
+ final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
+ final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
+
+ final boolean needStartTime = logSlowDelivery || logSlowDispatch;
+ final boolean needEndTime = logSlowDispatch;
+
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
- final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
- final long end;
+
+ final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
+ final long dispatchEnd;
try {
msg.target.dispatchMessage(msg);
- end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
+ dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
- if (slowDispatchThresholdMs > 0) {
- final long time = end - start;
- if (time > slowDispatchThresholdMs) {
- Slog.w(TAG, "Dispatch took " + time + "ms on "
- + Thread.currentThread().getName() + ", h=" +
- msg.target + " cb=" + msg.callback + " msg=" + msg.what);
+ if (logSlowDelivery) {
+ if (slowDeliveryDetected) {
+ if ((dispatchStart - msg.when) <= 10) {
+ Slog.w(TAG, "Drained");
+ slowDeliveryDetected = false;
+ }
+ } else {
+ if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
+ msg)) {
+ // Once we write a slow delivery log, suppress until the queue drains.
+ slowDeliveryDetected = true;
+ }
}
}
+ if (logSlowDispatch) {
+ showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
+ }
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
@@ -196,6 +234,19 @@ public final class Looper {
}
}
+ private static boolean showSlowLog(long threshold, long measureStart, long measureEnd,
+ String what, Message msg) {
+ final long actualTime = measureEnd - measureStart;
+ if (actualTime < threshold) {
+ return false;
+ }
+ // For slow delivery, the current message isn't really important, but log it anyway.
+ Slog.w(TAG, "Slow " + what + " took " + actualTime + "ms "
+ + Thread.currentThread().getName() + " h="
+ + msg.target.getClass().getName() + " c=" + msg.callback + " m=" + msg.what);
+ return true;
+ }
+
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
@@ -243,9 +294,13 @@ public final class Looper {
mTraceTag = traceTag;
}
- /** {@hide} */
- public void setSlowDispatchThresholdMs(long slowDispatchThresholdMs) {
+ /**
+ * Set a thresholds for slow dispatch/delivery log.
+ * {@hide}
+ */
+ public void setSlowLogThresholdMs(long slowDispatchThresholdMs, long slowDeliveryThresholdMs) {
mSlowDispatchThresholdMs = slowDispatchThresholdMs;
+ mSlowDeliveryThresholdMs = slowDeliveryThresholdMs;
}
/**
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index 9e3e386eedb2..5c99f6c87d7c 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -312,7 +312,7 @@ public class VolumeInfo implements Parcelable {
* {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}.
*/
public File getInternalPathForUser(int userId) {
- if (type == TYPE_PUBLIC && !isVisible()) {
+ if (type == TYPE_PUBLIC) {
// TODO: plumb through cleaner path from vold
return new File(path.replace("/storage/", "/mnt/media_rw/"));
} else {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index fdae19157569..f2d4542e960a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1785,6 +1785,12 @@ public final class Settings {
public static final int USER_SETUP_PERSONALIZATION_STARTED = 1;
/**
+ * User has snoozed personalization and will complete it later.
+ * @hide
+ */
+ public static final int USER_SETUP_PERSONALIZATION_PAUSED = 2;
+
+ /**
* User has completed setup personalization.
* @hide
*/
@@ -1795,6 +1801,7 @@ public final class Settings {
@IntDef({
USER_SETUP_PERSONALIZATION_NOT_STARTED,
USER_SETUP_PERSONALIZATION_STARTED,
+ USER_SETUP_PERSONALIZATION_PAUSED,
USER_SETUP_PERSONALIZATION_COMPLETE
})
public @interface UserSetupPersonalization {}
@@ -10604,18 +10611,30 @@ public final class Settings {
* App standby (app idle) specific settings.
* This is encoded as a key=value list, separated by commas. Ex:
* <p>
- * "idle_duration=5000,parole_interval=4500"
+ * "idle_duration=5000,parole_interval=4500,screen_thresholds=0/0/60000/120000"
* <p>
* All durations are in millis.
+ * Array values are separated by forward slashes
* The following keys are supported:
*
* <pre>
- * idle_duration2 (long)
- * wallclock_threshold (long)
- * parole_interval (long)
- * parole_duration (long)
+ * parole_interval (long)
+ * parole_window (long)
+ * parole_duration (long)
+ * screen_thresholds (long[4])
+ * elapsed_thresholds (long[4])
+ * strong_usage_duration (long)
+ * notification_seen_duration (long)
+ * system_update_usage_duration (long)
+ * prediction_timeout (long)
+ * sync_adapter_duration (long)
+ * exempted_sync_duration (long)
+ * system_interaction_duration (long)
+ * stable_charging_threshold (long)
*
* idle_duration (long) // This is deprecated and used to circumvent b/26355386.
+ * idle_duration2 (long) // deprecated
+ * wallclock_threshold (long) // deprecated
* </pre>
*
* <p>
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 309fa4afbd54..510626b4de4d 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -16,6 +16,10 @@
package android.service.notification;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.NotificationManager;
@@ -68,6 +72,7 @@ public class ZenModeConfig implements Parcelable {
public static final int SOURCE_STAR = 2;
public static final int MAX_SOURCE = SOURCE_STAR;
private static final int DEFAULT_SOURCE = SOURCE_CONTACT;
+ private static final int DEFAULT_CALLS_SOURCE = SOURCE_STAR;
public static final String EVENTS_DEFAULT_RULE_ID = "EVENTS_DEFAULT_RULE";
public static final String EVERY_NIGHT_DEFAULT_RULE_ID = "EVERY_NIGHT_DEFAULT_RULE";
@@ -93,13 +98,10 @@ public class ZenModeConfig implements Parcelable {
private static final boolean DEFAULT_ALLOW_REMINDERS = false;
private static final boolean DEFAULT_ALLOW_EVENTS = false;
private static final boolean DEFAULT_ALLOW_REPEAT_CALLERS = false;
- private static final boolean DEFAULT_ALLOW_SCREEN_OFF = false;
- private static final boolean DEFAULT_ALLOW_SCREEN_ON = false;
private static final boolean DEFAULT_CHANNELS_BYPASSING_DND = false;
- private static final int DEFAULT_SUPPRESSED_VISUAL_EFFECTS =
- Policy.getAllSuppressedVisualEffects();
+ private static final int DEFAULT_SUPPRESSED_VISUAL_EFFECTS = 0;
- public static final int XML_VERSION = 7;
+ public static final int XML_VERSION = 8;
public static final String ZEN_TAG = "zen";
private static final String ZEN_ATT_VERSION = "version";
private static final String ZEN_ATT_USER = "user";
@@ -151,12 +153,10 @@ public class ZenModeConfig implements Parcelable {
public boolean allowMessages = DEFAULT_ALLOW_MESSAGES;
public boolean allowReminders = DEFAULT_ALLOW_REMINDERS;
public boolean allowEvents = DEFAULT_ALLOW_EVENTS;
- public int allowCallsFrom = DEFAULT_SOURCE;
+ public int allowCallsFrom = DEFAULT_CALLS_SOURCE;
public int allowMessagesFrom = DEFAULT_SOURCE;
public int user = UserHandle.USER_SYSTEM;
public int suppressedVisualEffects = DEFAULT_SUPPRESSED_VISUAL_EFFECTS;
- public boolean allowWhenScreenOff = DEFAULT_ALLOW_SCREEN_OFF;
- public boolean allowWhenScreenOn = DEFAULT_ALLOW_SCREEN_ON;
public boolean areChannelsBypassingDnd = DEFAULT_CHANNELS_BYPASSING_DND;
public int version;
@@ -185,8 +185,6 @@ public class ZenModeConfig implements Parcelable {
automaticRules.put(ids[i], rules[i]);
}
}
- allowWhenScreenOff = source.readInt() == 1;
- allowWhenScreenOn = source.readInt() == 1;
allowAlarms = source.readInt() == 1;
allowMedia = source.readInt() == 1;
allowSystem = source.readInt() == 1;
@@ -219,8 +217,6 @@ public class ZenModeConfig implements Parcelable {
} else {
dest.writeInt(0);
}
- dest.writeInt(allowWhenScreenOff ? 1 : 0);
- dest.writeInt(allowWhenScreenOn ? 1 : 0);
dest.writeInt(allowAlarms ? 1 : 0);
dest.writeInt(allowMedia ? 1 : 0);
dest.writeInt(allowSystem ? 1 : 0);
@@ -242,8 +238,6 @@ public class ZenModeConfig implements Parcelable {
.append(",allowMessages=").append(allowMessages)
.append(",allowCallsFrom=").append(sourceToString(allowCallsFrom))
.append(",allowMessagesFrom=").append(sourceToString(allowMessagesFrom))
- .append(",allowWhenScreenOff=").append(allowWhenScreenOff)
- .append(",allowWhenScreenOn=").append(allowWhenScreenOn)
.append(",suppressedVisualEffects=").append(suppressedVisualEffects)
.append(",areChannelsBypassingDnd=").append(areChannelsBypassingDnd)
.append(",automaticRules=").append(automaticRules)
@@ -289,12 +283,6 @@ public class ZenModeConfig implements Parcelable {
if (allowMessagesFrom != to.allowMessagesFrom) {
d.addLine("allowMessagesFrom", allowMessagesFrom, to.allowMessagesFrom);
}
- if (allowWhenScreenOff != to.allowWhenScreenOff) {
- d.addLine("allowWhenScreenOff", allowWhenScreenOff, to.allowWhenScreenOff);
- }
- if (allowWhenScreenOn != to.allowWhenScreenOn) {
- d.addLine("allowWhenScreenOn", allowWhenScreenOn, to.allowWhenScreenOn);
- }
if (suppressedVisualEffects != to.suppressedVisualEffects) {
d.addLine("suppressedVisualEffects", suppressedVisualEffects,
to.suppressedVisualEffects);
@@ -404,8 +392,6 @@ public class ZenModeConfig implements Parcelable {
&& other.allowMessagesFrom == allowMessagesFrom
&& other.allowReminders == allowReminders
&& other.allowEvents == allowEvents
- && other.allowWhenScreenOff == allowWhenScreenOff
- && other.allowWhenScreenOn == allowWhenScreenOn
&& other.user == user
&& Objects.equals(other.automaticRules, automaticRules)
&& Objects.equals(other.manualRule, manualRule)
@@ -418,7 +404,7 @@ public class ZenModeConfig implements Parcelable {
return Objects.hash(allowAlarms, allowMedia, allowSystem, allowCalls,
allowRepeatCallers, allowMessages,
allowCallsFrom, allowMessagesFrom, allowReminders, allowEvents,
- allowWhenScreenOff, allowWhenScreenOn, user, automaticRules, manualRule,
+ user, automaticRules, manualRule,
suppressedVisualEffects, areChannelsBypassingDnd);
}
@@ -472,6 +458,7 @@ public class ZenModeConfig implements Parcelable {
final ZenModeConfig rt = new ZenModeConfig();
rt.version = safeInt(parser, ZEN_ATT_VERSION, XML_VERSION);
rt.user = safeInt(parser, ZEN_ATT_USER, rt.user);
+ boolean readSuppressedEffects = false;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
tag = parser.getName();
if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) {
@@ -502,17 +489,33 @@ public class ZenModeConfig implements Parcelable {
rt.allowCallsFrom = DEFAULT_SOURCE;
rt.allowMessagesFrom = DEFAULT_SOURCE;
}
- // continue to read even though we now have suppressedVisualEffects, in case
- // we need to revert to users' previous settings
- rt.allowWhenScreenOff =
- safeBoolean(parser, ALLOW_ATT_SCREEN_OFF, DEFAULT_ALLOW_SCREEN_OFF);
- rt.allowWhenScreenOn =
- safeBoolean(parser, ALLOW_ATT_SCREEN_ON, DEFAULT_ALLOW_SCREEN_ON);
rt.allowAlarms = safeBoolean(parser, ALLOW_ATT_ALARMS, DEFAULT_ALLOW_ALARMS);
rt.allowMedia = safeBoolean(parser, ALLOW_ATT_MEDIA,
DEFAULT_ALLOW_MEDIA);
rt.allowSystem = safeBoolean(parser, ALLOW_ATT_SYSTEM, DEFAULT_ALLOW_SYSTEM);
- } else if (DISALLOW_TAG.equals(tag)) {
+
+ // migrate old suppressed visual effects fields, if they still exist in the xml
+ Boolean allowWhenScreenOff = unsafeBoolean(parser, ALLOW_ATT_SCREEN_OFF);
+ if (allowWhenScreenOff != null) {
+ readSuppressedEffects = true;
+ if (allowWhenScreenOff) {
+ rt.suppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS
+ | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+ }
+ }
+ Boolean allowWhenScreenOn = unsafeBoolean(parser, ALLOW_ATT_SCREEN_ON);
+ if (allowWhenScreenOn != null) {
+ readSuppressedEffects = true;
+ if (allowWhenScreenOn) {
+ rt.suppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
+ }
+ }
+ if (readSuppressedEffects) {
+ Slog.d(TAG, "Migrated visual effects to " + rt.suppressedVisualEffects);
+ }
+ } else if (DISALLOW_TAG.equals(tag) && !readSuppressedEffects) {
+ // only read from suppressed visual effects field if we haven't just migrated
+ // the values from allowOn/allowOff, lest we wipe out those settings
rt.suppressedVisualEffects = safeInt(parser, DISALLOW_ATT_VISUAL_EFFECTS,
DEFAULT_SUPPRESSED_VISUAL_EFFECTS);
} else if (MANUAL_TAG.equals(tag)) {
@@ -552,8 +555,6 @@ public class ZenModeConfig implements Parcelable {
out.attribute(null, ALLOW_ATT_EVENTS, Boolean.toString(allowEvents));
out.attribute(null, ALLOW_ATT_CALLS_FROM, Integer.toString(allowCallsFrom));
out.attribute(null, ALLOW_ATT_MESSAGES_FROM, Integer.toString(allowMessagesFrom));
- out.attribute(null, ALLOW_ATT_SCREEN_OFF, Boolean.toString(allowWhenScreenOff));
- out.attribute(null, ALLOW_ATT_SCREEN_ON, Boolean.toString(allowWhenScreenOn));
out.attribute(null, ALLOW_ATT_ALARMS, Boolean.toString(allowAlarms));
out.attribute(null, ALLOW_ATT_MEDIA, Boolean.toString(allowMedia));
out.attribute(null, ALLOW_ATT_SYSTEM, Boolean.toString(allowSystem));
@@ -673,6 +674,12 @@ public class ZenModeConfig implements Parcelable {
return source >= SOURCE_ANYONE && source <= MAX_SOURCE;
}
+ private static Boolean unsafeBoolean(XmlPullParser parser, String att) {
+ final String val = parser.getAttributeValue(null, att);
+ if (TextUtils.isEmpty(val)) return null;
+ return Boolean.parseBoolean(val);
+ }
+
private static boolean safeBoolean(XmlPullParser parser, String att, boolean defValue) {
final String val = parser.getAttributeValue(null, att);
return safeBoolean(val, defValue);
diff --git a/core/java/android/transition/ChangeBounds.java b/core/java/android/transition/ChangeBounds.java
index 546f93a2e97a..56af3ac0f3c9 100644
--- a/core/java/android/transition/ChangeBounds.java
+++ b/core/java/android/transition/ChangeBounds.java
@@ -311,6 +311,38 @@ public class ChangeBounds extends Transition {
++numChanges;
}
if (numChanges > 0) {
+ if (view.getParent() instanceof ViewGroup) {
+ final ViewGroup parent = (ViewGroup) view.getParent();
+ parent.suppressLayout(true);
+ TransitionListener transitionListener = new TransitionListenerAdapter() {
+ boolean mCanceled = false;
+
+ @Override
+ public void onTransitionCancel(Transition transition) {
+ parent.suppressLayout(false);
+ mCanceled = true;
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ if (!mCanceled) {
+ parent.suppressLayout(false);
+ }
+ transition.removeListener(this);
+ }
+
+ @Override
+ public void onTransitionPause(Transition transition) {
+ parent.suppressLayout(false);
+ }
+
+ @Override
+ public void onTransitionResume(Transition transition) {
+ parent.suppressLayout(true);
+ }
+ };
+ addListener(transitionListener);
+ }
Animator anim;
if (!mResizeClip) {
view.setLeftTopRightBottom(startLeft, startTop, startRight, startBottom);
@@ -398,38 +430,6 @@ public class ChangeBounds extends Transition {
anim = TransitionUtils.mergeAnimators(positionAnimator,
clipAnimator);
}
- if (view.getParent() instanceof ViewGroup) {
- final ViewGroup parent = (ViewGroup) view.getParent();
- parent.suppressLayout(true);
- TransitionListener transitionListener = new TransitionListenerAdapter() {
- boolean mCanceled = false;
-
- @Override
- public void onTransitionCancel(Transition transition) {
- parent.suppressLayout(false);
- mCanceled = true;
- }
-
- @Override
- public void onTransitionEnd(Transition transition) {
- if (!mCanceled) {
- parent.suppressLayout(false);
- }
- transition.removeListener(this);
- }
-
- @Override
- public void onTransitionPause(Transition transition) {
- parent.suppressLayout(false);
- }
-
- @Override
- public void onTransitionResume(Transition transition) {
- parent.suppressLayout(true);
- }
- };
- addListener(transitionListener);
- }
return anim;
}
} else {
diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/ApkVerityBuilder.java
index f15e1a1a7c52..2dd0117d583d 100644
--- a/core/java/android/util/apk/ApkVerityBuilder.java
+++ b/core/java/android/util/apk/ApkVerityBuilder.java
@@ -134,7 +134,7 @@ abstract class ApkVerityBuilder {
assertSigningBlockAlignedAndHasFullPages(signatureInfo);
long signingBlockSize =
signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
- long dataSize = apk.length() - signingBlockSize - ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
+ long dataSize = apk.length() - signingBlockSize;
int[] levelOffset = calculateVerityLevelOffset(dataSize);
if (treeOutput != null) {
@@ -346,8 +346,8 @@ abstract class ApkVerityBuilder {
buffer.putLong(fileSize); // original file size
- buffer.put((byte) 0); // auth block offset, disabled here
- buffer.put((byte) 2); // extension count
+ buffer.put((byte) 2); // authenticated extension count
+ buffer.put((byte) 0); // unauthenticated extension count
buffer.put(salt); // salt (8 bytes)
skip(buffer, 22); // reserved
@@ -359,12 +359,6 @@ abstract class ApkVerityBuilder {
long signingBlockSize, long eocdOffset) {
// Snapshot of the FSVerity structs (subject to change once upstreamed).
//
- // struct fsverity_extension {
- // __le16 length;
- // u8 type;
- // u8 reserved[5];
- // };
- //
// struct fsverity_extension_elide {
// __le64 offset;
// __le64 length;
@@ -382,10 +376,10 @@ abstract class ApkVerityBuilder {
// struct fsverity_extension #1
final int kSizeOfFsverityElidedExtension = 16;
- buffer.putShort((short) // total size of extension, padded to 64-bit alignment
- (kSizeOfFsverityExtensionHeader + kSizeOfFsverityElidedExtension));
- buffer.put((byte) 0); // ID of elide extension
- skip(buffer, 5); // reserved
+ // First field is total size of extension, padded to 64-bit alignment
+ buffer.putInt(kSizeOfFsverityExtensionHeader + kSizeOfFsverityElidedExtension);
+ buffer.putShort((short) 1); // ID of elide extension
+ skip(buffer, 2); // reserved
// struct fsverity_extension_elide
buffer.putLong(signingBlockOffset);
@@ -398,9 +392,9 @@ abstract class ApkVerityBuilder {
+ 8 // offset size
+ ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
- buffer.putShort((short) kTotalSize);
- buffer.put((byte) 1); // ID of patch extension
- skip(buffer, 5); // reserved
+ buffer.putInt(kTotalSize); // Total size of extension, padded to 64-bit alignment
+ buffer.putShort((short) 2); // ID of patch extension
+ skip(buffer, 2); // reserved
// struct fsverity_extension_patch
buffer.putLong(eocdOffset + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET); // offset
@@ -412,7 +406,7 @@ abstract class ApkVerityBuilder {
if (kPadding == kExtensionSizeAlignment) {
kPadding = 0;
}
- skip(buffer, kPadding); // padding
+ skip(buffer, kPadding); // padding
}
buffer.flip();
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 7e5464761e38..db34856e0ad6 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -700,15 +700,9 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
mIsCreating = false;
if (mSurfaceControl != null && !mSurfaceCreated) {
mSurface.release();
- // If we are not in the stopped state, then the destruction of the Surface
- // represents a visual change we need to display, and we should go ahead
- // and destroy the SurfaceControl. However if we are in the stopped state,
- // we can just leave the Surface around so it can be a part of animations,
- // and we let the life-time be tied to the parent surface.
- if (!mWindowStopped) {
- mSurfaceControl.destroy();
- mSurfaceControl = null;
- }
+
+ mSurfaceControl.destroy();
+ mSurfaceControl = null;
}
}
} catch (Exception ex) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 6b16d42ac7ef..380707996436 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -20850,7 +20850,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
// If this isn't laid out yet, focus assignment will be handled during the "deferment/
// backtracking" of requestFocus during layout, so don't touch focus here.
- if (!sCanFocusZeroSized && isLayoutValid()) {
+ if (!sCanFocusZeroSized && isLayoutValid()
+ // Don't touch focus if animating
+ && !(mParent instanceof ViewGroup && ((ViewGroup) mParent).isLayoutSuppressed())) {
if (newWidth <= 0 || newHeight <= 0) {
if (hasFocus()) {
clearFocus();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4bd6fc8b665f..239185e5c25d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -245,7 +245,7 @@ public final class ViewRootImpl implements ViewParent,
final WindowLeaked mLocation;
- final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
+ public final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
final W mWindow;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 1c2e43e1a562..6bacdfe052a5 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -901,7 +901,7 @@ public class AccessibilityNodeInfo implements Parcelable {
* Refreshes this info with the latest state of the view it represents, and request new
* data be added by the View.
*
- * @param extraDataKey A bitmask of the extra data requested. Data that must be requested
+ * @param extraDataKey The extra data requested. Data that must be requested
* with this mechanism is generally expensive to retrieve, so should only be
* requested when needed. See
* {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY} and
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index f1a1457e9d5c..929496f2d237 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -38,7 +38,6 @@ import android.os.Message;
import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.DisplayListCanvas;
-import android.view.LayoutInflater;
import android.view.PixelCopy;
import android.view.RenderNode;
import android.view.Surface;
@@ -71,8 +70,6 @@ public final class Magnifier {
private final int[] mViewCoordinatesInSurface;
// The window containing the magnifier.
private InternalPopupWindow mWindow;
- // The center coordinates of the window containing the magnifier.
- private final Point mWindowCoords = new Point();
// The width of the window containing the magnifier.
private final int mWindowWidth;
// The height of the window containing the magnifier.
@@ -87,8 +84,18 @@ public final class Magnifier {
private final float mWindowElevation;
// The corner radius of the window containing the magnifier.
private final float mWindowCornerRadius;
- // The center coordinates of the content that is to be magnified.
+ // The parent surface for the magnifier surface.
+ private SurfaceInfo mParentSurface;
+ // The surface where the content will be copied from.
+ private SurfaceInfo mContentCopySurface;
+ // The center coordinates of the window containing the magnifier.
+ private final Point mWindowCoords = new Point();
+ // The center coordinates of the content to be magnified,
+ // which can potentially contain a region outside the magnified view.
private final Point mCenterZoomCoords = new Point();
+ // The center coordinates of the content to be magnified,
+ // clamped inside the visible region of the magnified view.
+ private final Point mClampedCenterZoomCoords = new Point();
// Variables holding previous states, used for detecting redundant calls and invalidation.
private final Point mPrevStartCoordsInSurface = new Point(
NONEXISTENT_PREVIOUS_CONFIG_VALUE, NONEXISTENT_PREVIOUS_CONFIG_VALUE);
@@ -108,8 +115,6 @@ public final class Magnifier {
public Magnifier(@NonNull View view) {
mView = Preconditions.checkNotNull(view);
final Context context = mView.getContext();
- final View content = LayoutInflater.from(context).inflate(R.layout.magnifier, null);
- content.findViewById(R.id.magnifier_inner).setClipToOutline(true);
mWindowWidth = context.getResources().getDimensionPixelSize(R.dimen.magnifier_width);
mWindowHeight = context.getResources().getDimensionPixelSize(R.dimen.magnifier_height);
mWindowElevation = context.getResources().getDimension(R.dimen.magnifier_elevation);
@@ -155,22 +160,17 @@ public final class Magnifier {
xPosInView = Math.max(0, Math.min(xPosInView, mView.getWidth()));
yPosInView = Math.max(0, Math.min(yPosInView, mView.getHeight()));
- configureCoordinates(xPosInView, yPosInView);
-
- // Clamp the startX location to avoid magnifying content which does not belong
- // to the magnified view. This will not take into account overlapping views.
- final Rect viewVisibleRegion = new Rect();
- mView.getGlobalVisibleRect(viewVisibleRegion);
- final int startX = Math.max(viewVisibleRegion.left, Math.min(
- mCenterZoomCoords.x - mBitmapWidth / 2,
- viewVisibleRegion.right - mBitmapWidth));
- final int startY = mCenterZoomCoords.y - mBitmapHeight / 2;
+ obtainSurfaces();
+ obtainContentCoordinates(xPosInView, yPosInView);
+ obtainWindowCoordinates();
+ final int startX = mClampedCenterZoomCoords.x - mBitmapWidth / 2;
+ final int startY = mClampedCenterZoomCoords.y - mBitmapHeight / 2;
if (xPosInView != mPrevPosInView.x || yPosInView != mPrevPosInView.y) {
if (mWindow == null) {
synchronized (mLock) {
mWindow = new InternalPopupWindow(mView.getContext(), mView.getDisplay(),
- getValidParentSurfaceForMagnifier(),
+ mParentSurface.mSurface,
mWindowWidth, mWindowHeight, mWindowElevation, mWindowCornerRadius,
Handler.getMain() /* draw the magnifier on the UI thread */, mLock,
mCallback);
@@ -204,6 +204,7 @@ public final class Magnifier {
*/
public void update() {
if (mWindow != null) {
+ obtainSurfaces();
// Update the content shown in the magnifier.
performPixelCopy(mPrevStartCoordsInSurface.x, mPrevStartCoordsInSurface.y,
false /* update window position */);
@@ -235,35 +236,66 @@ public final class Magnifier {
/**
* @hide
+ *
+ * @return The top left coordinates of the magnifier, relative to the parent window.
*/
@Nullable
public Point getWindowCoords() {
if (mWindow == null) {
return null;
}
- return new Point(mWindow.mLastDrawContentPositionX, mWindow.mLastDrawContentPositionY);
+ final Rect surfaceInsets = mView.getViewRootImpl().mWindowAttributes.surfaceInsets;
+ return new Point(mWindow.mLastDrawContentPositionX - surfaceInsets.left,
+ mWindow.mLastDrawContentPositionY - surfaceInsets.top);
}
- @Nullable
- private Surface getValidParentSurfaceForMagnifier() {
+ /**
+ * Retrieves the surfaces used by the magnifier:
+ * - a parent surface for the magnifier surface. This will usually be the main app window.
+ * - a surface where the magnified content will be copied from. This will be the main app
+ * window unless the magnified view is a SurfaceView, in which case its backing surface
+ * will be used.
+ */
+ private void obtainSurfaces() {
+ // Get the main window surface.
+ SurfaceInfo validMainWindowSurface = SurfaceInfo.NULL;
if (mView.getViewRootImpl() != null) {
- final Surface mainWindowSurface = mView.getViewRootImpl().mSurface;
+ final ViewRootImpl viewRootImpl = mView.getViewRootImpl();
+ final Surface mainWindowSurface = viewRootImpl.mSurface;
if (mainWindowSurface != null && mainWindowSurface.isValid()) {
- return mainWindowSurface;
+ final Rect surfaceInsets = viewRootImpl.mWindowAttributes.surfaceInsets;
+ final int surfaceWidth =
+ viewRootImpl.getWidth() + surfaceInsets.left + surfaceInsets.right;
+ final int surfaceHeight =
+ viewRootImpl.getHeight() + surfaceInsets.top + surfaceInsets.bottom;
+ validMainWindowSurface =
+ new SurfaceInfo(mainWindowSurface, surfaceWidth, surfaceHeight, true);
}
}
+ // Get the surface backing the magnified view, if it is a SurfaceView.
+ SurfaceInfo validSurfaceViewSurface = SurfaceInfo.NULL;
if (mView instanceof SurfaceView) {
- final Surface surfaceViewSurface = ((SurfaceView) mView).getHolder().getSurface();
+ final SurfaceHolder surfaceHolder = ((SurfaceView) mView).getHolder();
+ final Surface surfaceViewSurface = surfaceHolder.getSurface();
if (surfaceViewSurface != null && surfaceViewSurface.isValid()) {
- return surfaceViewSurface;
+ final Rect surfaceFrame = surfaceHolder.getSurfaceFrame();
+ validSurfaceViewSurface = new SurfaceInfo(surfaceViewSurface,
+ surfaceFrame.right, surfaceFrame.bottom, false);
}
}
- return null;
+
+ // Choose the parent surface for the magnifier and the source surface for the content.
+ mParentSurface = validMainWindowSurface != SurfaceInfo.NULL
+ ? validMainWindowSurface : validSurfaceViewSurface;
+ mContentCopySurface = mView instanceof SurfaceView
+ ? validSurfaceViewSurface : validMainWindowSurface;
}
- private void configureCoordinates(final float xPosInView, final float yPosInView) {
- // Compute the coordinates of the center of the content going to be displayed in the
- // magnifier. These are relative to the surface the content is copied from.
+ /**
+ * Computes the coordinates of the center of the content going to be displayed in the
+ * magnifier. These are relative to the surface the content is copied from.
+ */
+ private void obtainContentCoordinates(final float xPosInView, final float yPosInView) {
final float posX;
final float posY;
mView.getLocationInSurface(mViewCoordinatesInSurface);
@@ -278,61 +310,63 @@ public final class Magnifier {
mCenterZoomCoords.x = Math.round(posX);
mCenterZoomCoords.y = Math.round(posY);
+ // Clamp the x location to avoid magnifying content which does not belong
+ // to the magnified view. This will not take into account overlapping views.
+ final Rect viewVisibleRegion = new Rect();
+ mView.getGlobalVisibleRect(viewVisibleRegion);
+ if (mView.getViewRootImpl() != null) {
+ // Clamping coordinates relative to the surface, not to the window.
+ final Rect surfaceInsets = mView.getViewRootImpl().mWindowAttributes.surfaceInsets;
+ viewVisibleRegion.offset(surfaceInsets.left, surfaceInsets.top);
+ }
+ if (mView instanceof SurfaceView) {
+ // If we copy content from a SurfaceView, clamp coordinates relative to it.
+ viewVisibleRegion.offset(-mViewCoordinatesInSurface[0], -mViewCoordinatesInSurface[1]);
+ }
+ mClampedCenterZoomCoords.x = Math.max(viewVisibleRegion.left + mBitmapWidth / 2, Math.min(
+ mCenterZoomCoords.x, viewVisibleRegion.right - mBitmapWidth / 2));
+ mClampedCenterZoomCoords.y = mCenterZoomCoords.y;
+ }
+
+ private void obtainWindowCoordinates() {
// Compute the position of the magnifier window. Again, this has to be relative to the
// surface of the magnified view, as this surface is the parent of the magnifier surface.
final int verticalOffset = mView.getContext().getResources().getDimensionPixelSize(
R.dimen.magnifier_offset);
mWindowCoords.x = mCenterZoomCoords.x - mWindowWidth / 2;
mWindowCoords.y = mCenterZoomCoords.y - mWindowHeight / 2 - verticalOffset;
- if (mView instanceof SurfaceView && mView.getViewRootImpl() != null) {
- // TODO: deduplicate against the first part of #getValidParentSurfaceForMagnifier()
- final Surface mainWindowSurface = mView.getViewRootImpl().mSurface;
- if (mainWindowSurface != null && mainWindowSurface.isValid()) {
- mWindowCoords.x += mViewCoordinatesInSurface[0];
- mWindowCoords.y += mViewCoordinatesInSurface[1];
- }
+ if (mParentSurface != mContentCopySurface) {
+ mWindowCoords.x += mViewCoordinatesInSurface[0];
+ mWindowCoords.y += mViewCoordinatesInSurface[1];
}
}
private void performPixelCopy(final int startXInSurface, final int startYInSurface,
final boolean updateWindowPosition) {
- // Get the view surface where the content will be copied from.
- final Surface surface;
- final int surfaceWidth;
- final int surfaceHeight;
- if (mView instanceof SurfaceView) {
- final SurfaceHolder surfaceHolder = ((SurfaceView) mView).getHolder();
- surface = surfaceHolder.getSurface();
- surfaceWidth = surfaceHolder.getSurfaceFrame().right;
- surfaceHeight = surfaceHolder.getSurfaceFrame().bottom;
- } else if (mView.getViewRootImpl() != null) {
- final ViewRootImpl viewRootImpl = mView.getViewRootImpl();
- surface = viewRootImpl.mSurface;
- surfaceWidth = viewRootImpl.getWidth();
- surfaceHeight = viewRootImpl.getHeight();
- } else {
- surface = null;
- surfaceWidth = NONEXISTENT_PREVIOUS_CONFIG_VALUE;
- surfaceHeight = NONEXISTENT_PREVIOUS_CONFIG_VALUE;
- }
-
- if (surface == null || !surface.isValid()) {
+ if (mContentCopySurface.mSurface == null || !mContentCopySurface.mSurface.isValid()) {
return;
}
-
// Clamp copy coordinates inside the surface to avoid displaying distorted content.
final int clampedStartXInSurface = Math.max(0,
- Math.min(startXInSurface, surfaceWidth - mBitmapWidth));
+ Math.min(startXInSurface, mContentCopySurface.mWidth - mBitmapWidth));
final int clampedStartYInSurface = Math.max(0,
- Math.min(startYInSurface, surfaceHeight - mBitmapHeight));
+ Math.min(startYInSurface, mContentCopySurface.mHeight - mBitmapHeight));
// Clamp window coordinates inside the parent surface, to avoid displaying
// the magnifier out of screen or overlapping with system insets.
- final Rect insets = mView.getRootWindowInsets().getSystemWindowInsets();
- final int windowCoordsX = Math.max(insets.left,
- Math.min(surfaceWidth - mWindowWidth - insets.right, mWindowCoords.x));
- final int windowCoordsY = Math.max(insets.top,
- Math.min(surfaceHeight - mWindowHeight - insets.bottom, mWindowCoords.y));
+ final Rect windowBounds;
+ if (mParentSurface.mIsMainWindowSurface) {
+ final Rect systemInsets = mView.getRootWindowInsets().getSystemWindowInsets();
+ windowBounds = new Rect(systemInsets.left, systemInsets.top,
+ mParentSurface.mWidth - systemInsets.right,
+ mParentSurface.mHeight - systemInsets.bottom);
+ } else {
+ windowBounds = new Rect(0, 0, mParentSurface.mWidth, mParentSurface.mHeight);
+ }
+ final int windowCoordsX = Math.max(windowBounds.left,
+ Math.min(windowBounds.right - mWindowWidth, mWindowCoords.x));
+ final int windowCoordsY = Math.max(windowBounds.top,
+ Math.min(windowBounds.bottom - mWindowHeight, mWindowCoords.y));
// Perform the pixel copy.
mPixelCopyRequestRect.set(clampedStartXInSurface,
@@ -342,7 +376,7 @@ public final class Magnifier {
final InternalPopupWindow currentWindowInstance = mWindow;
final Bitmap bitmap =
Bitmap.createBitmap(mBitmapWidth, mBitmapHeight, Bitmap.Config.ARGB_8888);
- PixelCopy.request(surface, mPixelCopyRequestRect, bitmap,
+ PixelCopy.request(mContentCopySurface.mSurface, mPixelCopyRequestRect, bitmap,
result -> {
synchronized (mLock) {
if (mWindow != currentWindowInstance) {
@@ -362,6 +396,26 @@ public final class Magnifier {
}
/**
+ * Contains a surface and metadata corresponding to it.
+ */
+ private static class SurfaceInfo {
+ public static final SurfaceInfo NULL = new SurfaceInfo(null, 0, 0, false);
+
+ private Surface mSurface;
+ private int mWidth;
+ private int mHeight;
+ private boolean mIsMainWindowSurface;
+
+ SurfaceInfo(final Surface surface, final int width, final int height,
+ final boolean isMainWindowSurface) {
+ mSurface = surface;
+ mWidth = width;
+ mHeight = height;
+ mIsMainWindowSurface = isMainWindowSurface;
+ }
+ }
+
+ /**
* Magnifier's own implementation of PopupWindow-similar floating window.
* This exists to ensure frame-synchronization between window position updates and window
* content updates. By using a PopupWindow, these events would happen in different frames,
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index ced66cd275ea..e7c3a47348d0 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -1373,7 +1373,7 @@ public class ProgressBar extends View {
* indicator. To animate the visual position to the target value, use
* {@link #setProgress(int, boolean)}}.
*
- * @param progress the new progress, between 0 and {@link #getMax()}
+ * @param progress the new progress, between {@link #getMin()} and {@link #getMax()}
*
* @see #setIndeterminate(boolean)
* @see #isIndeterminate()
@@ -1392,7 +1392,7 @@ public class ProgressBar extends View {
* Animation does not affect the result of {@link #getProgress()}, which
* will return the target value immediately after this method is called.
*
- * @param progress the new progress value, between 0 and {@link #getMax()}
+ * @param progress the new progress value, between {@link #getMin()} and {@link #getMax()}
* @param animate {@code true} to animate between the current and target
* values or {@code false} to not animate
*/
@@ -1425,7 +1425,8 @@ public class ProgressBar extends View {
* anything if the progress bar is in indeterminate mode.
* </p>
*
- * @param secondaryProgress the new secondary progress, between 0 and {@link #getMax()}
+ * @param secondaryProgress the new secondary progress, between {@link #getMin()} and
+ * {@link #getMax()}
* @see #setIndeterminate(boolean)
* @see #isIndeterminate()
* @see #getSecondaryProgress()
@@ -1455,7 +1456,7 @@ public class ProgressBar extends View {
* <p>Get the progress bar's current level of progress. Return 0 when the
* progress bar is in indeterminate mode.</p>
*
- * @return the current progress, between 0 and {@link #getMax()}
+ * @return the current progress, between {@link #getMin()} and {@link #getMax()}
*
* @see #setIndeterminate(boolean)
* @see #isIndeterminate()
@@ -1472,7 +1473,7 @@ public class ProgressBar extends View {
* <p>Get the progress bar's current level of secondary progress. Return 0 when the
* progress bar is in indeterminate mode.</p>
*
- * @return the current secondary progress, between 0 and {@link #getMax()}
+ * @return the current secondary progress, between {@link #getMin()} and {@link #getMax()}
*
* @see #setIndeterminate(boolean)
* @see #isIndeterminate()
@@ -1990,7 +1991,8 @@ public class ProgressBar extends View {
if (!isIndeterminate()) {
AccessibilityNodeInfo.RangeInfo rangeInfo = AccessibilityNodeInfo.RangeInfo.obtain(
- AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_INT, 0, getMax(), getProgress());
+ AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_INT, getMin(), getMax(),
+ getProgress());
info.setRangeInfo(rangeInfo);
}
}
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index a075705c2e40..b591163e8728 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -85,6 +85,14 @@ public abstract class FileSystemProvider extends DocumentsProvider {
protected abstract Uri buildNotificationUri(String docId);
+ /**
+ * Callback indicating that the given document has been modified. This gives
+ * the provider a hook to invalidate cached data, such as {@code sdcardfs}.
+ */
+ protected void onDocIdChanged(String docId) {
+ // Default is no-op
+ }
+
@Override
public boolean onCreate() {
throw new UnsupportedOperationException(
@@ -185,6 +193,7 @@ public abstract class FileSystemProvider extends DocumentsProvider {
throw new IllegalStateException("Failed to mkdir " + file);
}
childId = getDocIdForFile(file);
+ onDocIdChanged(childId);
addFolderToMediaStore(getFileForDocId(childId, true));
} else {
try {
@@ -192,6 +201,7 @@ public abstract class FileSystemProvider extends DocumentsProvider {
throw new IllegalStateException("Failed to touch " + file);
}
childId = getDocIdForFile(file);
+ onDocIdChanged(childId);
} catch (IOException e) {
throw new IllegalStateException("Failed to touch " + file + ": " + e);
}
@@ -227,16 +237,20 @@ public abstract class FileSystemProvider extends DocumentsProvider {
final File before = getFileForDocId(docId);
final File after = FileUtils.buildUniqueFile(before.getParentFile(), displayName);
- final File visibleFileBefore = getFileForDocId(docId, true);
if (!before.renameTo(after)) {
throw new IllegalStateException("Failed to rename to " + after);
}
final String afterDocId = getDocIdForFile(after);
- moveInMediaStore(visibleFileBefore, getFileForDocId(afterDocId, true));
+ onDocIdChanged(docId);
+ onDocIdChanged(afterDocId);
+
+ final File beforeVisibleFile = getFileForDocId(docId, true);
+ final File afterVisibleFile = getFileForDocId(afterDocId, true);
+ moveInMediaStore(beforeVisibleFile, afterVisibleFile);
if (!TextUtils.equals(docId, afterDocId)) {
- scanFile(after);
+ scanFile(afterVisibleFile);
return afterDocId;
} else {
return null;
@@ -259,6 +273,8 @@ public abstract class FileSystemProvider extends DocumentsProvider {
}
final String docId = getDocIdForFile(after);
+ onDocIdChanged(sourceDocumentId);
+ onDocIdChanged(docId);
moveInMediaStore(visibleFileBefore, getFileForDocId(docId, true));
return docId;
@@ -308,6 +324,7 @@ public abstract class FileSystemProvider extends DocumentsProvider {
throw new IllegalStateException("Failed to delete " + file);
}
+ onDocIdChanged(docId);
removeFromMediaStore(visibleFile, isDirectory);
}
@@ -418,7 +435,10 @@ public abstract class FileSystemProvider extends DocumentsProvider {
try {
// When finished writing, kick off media scanner
return ParcelFileDescriptor.open(
- file, pfdMode, mHandler, (IOException e) -> scanFile(visibleFile));
+ file, pfdMode, mHandler, (IOException e) -> {
+ onDocIdChanged(documentId);
+ scanFile(visibleFile);
+ });
} catch (IOException e) {
throw new FileNotFoundException("Failed to open for writing: " + e);
}
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index 8a456d1c6f58..e2b8f7dca680 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -94,14 +94,6 @@ public class PackageHelper {
abstract public boolean getAllow3rdPartyOnInternalConfig(Context context);
abstract public ApplicationInfo getExistingAppInfo(Context context, String packageName);
abstract public File getDataDirectory();
-
- public boolean fitsOnInternalStorage(Context context, SessionParams params)
- throws IOException {
- StorageManager storage = getStorageManager(context);
- final UUID target = storage.getUuidForPath(getDataDirectory());
- return (params.sizeBytes <= storage.getAllocatableBytes(target,
- translateAllocateFlags(params.installFlags)));
- }
}
private synchronized static TestableInterface getDefaultTestableInterface() {
@@ -175,6 +167,7 @@ public class PackageHelper {
@VisibleForTesting
public static String resolveInstallVolume(Context context, SessionParams params,
TestableInterface testInterface) throws IOException {
+ final StorageManager storageManager = testInterface.getStorageManager(context);
final boolean forceAllowOnExternal = testInterface.getForceAllowOnExternalSetting(context);
final boolean allow3rdPartyOnInternal =
testInterface.getAllow3rdPartyOnInternalConfig(context);
@@ -183,42 +176,43 @@ public class PackageHelper {
ApplicationInfo existingInfo = testInterface.getExistingAppInfo(context,
params.appPackageName);
- final boolean fitsOnInternal = testInterface.fitsOnInternalStorage(context, params);
- final StorageManager storageManager =
- testInterface.getStorageManager(context);
-
- // System apps always forced to internal storage
- if (existingInfo != null && existingInfo.isSystemApp()) {
- if (fitsOnInternal) {
- return StorageManager.UUID_PRIVATE_INTERNAL;
- } else {
- throw new IOException("Not enough space on existing volume "
- + existingInfo.volumeUuid + " for system app " + params.appPackageName
- + " upgrade");
- }
- }
-
- // Now deal with non-system apps.
+ // Figure out best candidate volume, and also if we fit on internal
final ArraySet<String> allCandidates = new ArraySet<>();
+ boolean fitsOnInternal = false;
VolumeInfo bestCandidate = null;
long bestCandidateAvailBytes = Long.MIN_VALUE;
for (VolumeInfo vol : storageManager.getVolumes()) {
- boolean isInternalStorage = ID_PRIVATE_INTERNAL.equals(vol.id);
- if (vol.type == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()
- && (!isInternalStorage || allow3rdPartyOnInternal)) {
+ if (vol.type == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()) {
+ final boolean isInternalStorage = ID_PRIVATE_INTERNAL.equals(vol.id);
final UUID target = storageManager.getUuidForPath(new File(vol.path));
final long availBytes = storageManager.getAllocatableBytes(target,
translateAllocateFlags(params.installFlags));
- if (availBytes >= params.sizeBytes) {
- allCandidates.add(vol.fsUuid);
+ if (isInternalStorage) {
+ fitsOnInternal = (params.sizeBytes <= availBytes);
}
- if (availBytes >= bestCandidateAvailBytes) {
- bestCandidate = vol;
- bestCandidateAvailBytes = availBytes;
+ if (!isInternalStorage || allow3rdPartyOnInternal) {
+ if (availBytes >= params.sizeBytes) {
+ allCandidates.add(vol.fsUuid);
+ }
+ if (availBytes >= bestCandidateAvailBytes) {
+ bestCandidate = vol;
+ bestCandidateAvailBytes = availBytes;
+ }
}
}
}
+ // System apps always forced to internal storage
+ if (existingInfo != null && existingInfo.isSystemApp()) {
+ if (fitsOnInternal) {
+ return StorageManager.UUID_PRIVATE_INTERNAL;
+ } else {
+ throw new IOException("Not enough space on existing volume "
+ + existingInfo.volumeUuid + " for system app " + params.appPackageName
+ + " upgrade");
+ }
+ }
+
// If app expresses strong desire for internal storage, honor it
if (!forceAllowOnExternal
&& params.installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java
index 98afebc51bcd..c4d08c7dc5d6 100644
--- a/core/java/com/android/internal/net/NetworkStatsFactory.java
+++ b/core/java/com/android/internal/net/NetworkStatsFactory.java
@@ -56,8 +56,6 @@ public class NetworkStatsFactory {
private static final boolean USE_NATIVE_PARSING = true;
private static final boolean SANITY_CHECK_NATIVE = false;
- /** Path to {@code /proc/net/dev}. */
- private final File mStatsIfaceDev;
/** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */
private final File mStatsXtIfaceAll;
/** Path to {@code /proc/net/xt_qtaguid/iface_stat_fmt}. */
@@ -133,47 +131,16 @@ public class NetworkStatsFactory {
@VisibleForTesting
public NetworkStatsFactory(File procRoot, boolean useBpfStats) {
- mStatsIfaceDev = new File(procRoot, "net/dev");
mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all");
mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt");
mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
mUseBpfStats = useBpfStats;
}
- @VisibleForTesting
- public NetworkStats readNetworkStatsIfaceDev() throws IOException {
- final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
-
+ public NetworkStats readBpfNetworkStatsDev() throws IOException {
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
- final NetworkStats.Entry entry = new NetworkStats.Entry();
-
- BufferedReader reader = null;
- try {
- reader = new BufferedReader(new FileReader(mStatsIfaceDev));
-
- // skip first two header lines
- reader.readLine();
- reader.readLine();
-
- // parse remaining lines
- String line;
- while ((line = reader.readLine()) != null) {
- String[] values = line.trim().split("\\:?\\s+");
- entry.iface = values[0];
- entry.uid = UID_ALL;
- entry.set = SET_ALL;
- entry.tag = TAG_NONE;
- entry.rxBytes = Long.parseLong(values[1]);
- entry.rxPackets = Long.parseLong(values[2]);
- entry.txBytes = Long.parseLong(values[9]);
- entry.txPackets = Long.parseLong(values[10]);
- stats.addValues(entry);
- }
- } catch (NullPointerException|NumberFormatException e) {
- throw new ProtocolException("problem parsing stats", e);
- } finally {
- IoUtils.closeQuietly(reader);
- StrictMode.setThreadPolicy(savedPolicy);
+ if (nativeReadNetworkStatsDev(stats) != 0) {
+ throw new IOException("Failed to parse bpf iface stats");
}
return stats;
}
@@ -188,9 +155,9 @@ public class NetworkStatsFactory {
*/
public NetworkStats readNetworkStatsSummaryDev() throws IOException {
- // Return the stats get from /proc/net/dev if switched to bpf module.
+ // Return xt_bpf stats if switched to bpf module.
if (mUseBpfStats)
- return readNetworkStatsIfaceDev();
+ return readBpfNetworkStatsDev();
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
@@ -244,9 +211,9 @@ public class NetworkStatsFactory {
*/
public NetworkStats readNetworkStatsSummaryXt() throws IOException {
- // Return the stats get from /proc/net/dev if qtaguid module is replaced.
+ // Return xt_bpf stats if qtaguid module is replaced.
if (mUseBpfStats)
- return readNetworkStatsIfaceDev();
+ return readBpfNetworkStatsDev();
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
@@ -408,4 +375,7 @@ public class NetworkStatsFactory {
@VisibleForTesting
public static native int nativeReadNetworkStatsDetail(NetworkStats stats, String path,
int limitUid, String[] limitIfaces, int limitTag, boolean useBpfStats);
+
+ @VisibleForTesting
+ public static native int nativeReadNetworkStatsDev(NetworkStats stats);
}
diff --git a/core/java/com/android/internal/os/BackgroundThread.java b/core/java/com/android/internal/os/BackgroundThread.java
index 7558f8cee233..eada142dd3c6 100644
--- a/core/java/com/android/internal/os/BackgroundThread.java
+++ b/core/java/com/android/internal/os/BackgroundThread.java
@@ -18,12 +18,15 @@ package com.android.internal.os;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.Looper;
import android.os.Trace;
/**
* Shared singleton background thread for each process.
*/
public final class BackgroundThread extends HandlerThread {
+ private static final long SLOW_DISPATCH_THRESHOLD_MS = 10_000;
+ private static final long SLOW_DELIVERY_THRESHOLD_MS = 30_000;
private static BackgroundThread sInstance;
private static Handler sHandler;
@@ -35,7 +38,10 @@ public final class BackgroundThread extends HandlerThread {
if (sInstance == null) {
sInstance = new BackgroundThread();
sInstance.start();
- sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
+ final Looper looper = sInstance.getLooper();
+ looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
+ looper.setSlowLogThresholdMs(
+ SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
sHandler = new Handler(sInstance.getLooper());
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index be834987e73f..7703052bc327 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -4084,7 +4084,8 @@ public class BatteryStatsImpl extends BatteryStats {
boolean ensureStartClockTime(final long currentTime) {
final long ABOUT_ONE_YEAR = 365*24*60*60*1000L;
- if (currentTime > ABOUT_ONE_YEAR && mStartClockTime < (currentTime-ABOUT_ONE_YEAR)) {
+ if ((currentTime > ABOUT_ONE_YEAR && mStartClockTime < (currentTime-ABOUT_ONE_YEAR))
+ || (mStartClockTime > currentTime)) {
// If the start clock time has changed by more than a year, then presumably
// the previous time was completely bogus. So we are going to figure out a
// new time based on how much time has elapsed since we started counting.
diff --git a/core/java/com/android/internal/policy/DecorContext.java b/core/java/com/android/internal/policy/DecorContext.java
index eac9f64f3fa0..cd80d53a7546 100644
--- a/core/java/com/android/internal/policy/DecorContext.java
+++ b/core/java/com/android/internal/policy/DecorContext.java
@@ -23,6 +23,8 @@ import android.view.ContextThemeWrapper;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
+import java.lang.ref.WeakReference;
+
/**
* Context for decor views which can be seeded with pure application context and not depend on the
* activity, but still provide some of the facilities that Activity has,
@@ -35,9 +37,12 @@ class DecorContext extends ContextThemeWrapper {
private WindowManager mWindowManager;
private Resources mActivityResources;
- public DecorContext(Context context, Resources activityResources) {
+ private WeakReference<Context> mActivityContext;
+
+ public DecorContext(Context context, Context activityContext) {
super(context, null);
- mActivityResources = activityResources;
+ mActivityContext = new WeakReference<>(activityContext);
+ mActivityResources = activityContext.getResources();
}
void setPhoneWindow(PhoneWindow phoneWindow) {
@@ -60,6 +65,13 @@ class DecorContext extends ContextThemeWrapper {
@Override
public Resources getResources() {
+ Context activityContext = mActivityContext.get();
+ // Attempt to update the local cached Resources from the activity context. If the activity
+ // is no longer around, return the old cached values.
+ if (activityContext != null) {
+ mActivityResources = activityContext.getResources();
+ }
+
return mActivityResources;
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index eadefc919934..cc95df7724ba 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -41,7 +41,6 @@ import java.util.List;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
-import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -55,7 +54,6 @@ import android.graphics.Region;
import android.graphics.Shader;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.os.RemoteException;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
@@ -1844,6 +1842,13 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
}
@Override
+ public Resources getResources() {
+ // Make sure the Resources object is propogated from the Context since it can be updated in
+ // the Context object.
+ return getContext().getResources();
+ }
+
+ @Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index 3af3e2ad2772..a3c7a9ef6f91 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -344,7 +344,7 @@ public class DividerSnapAlgorithm {
if (dockedSide == DOCKED_LEFT) {
position += mInsets.left;
} else if (dockedSide == DOCKED_RIGHT) {
- position = mDisplayWidth - position - mInsets.right;
+ position = mDisplayWidth - position - mInsets.right - mDividerSize;
}
}
mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE));
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 528888fbaab6..7ea023eb50b2 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -2299,7 +2299,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (applicationContext == null) {
context = getContext();
} else {
- context = new DecorContext(applicationContext, getContext().getResources());
+ context = new DecorContext(applicationContext, getContext());
if (mTheme != -1) {
context.setTheme(mTheme);
}
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index 3f73237da12b..4104b6ca9d2a 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -118,7 +118,8 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou
ViewGroup parent = (ViewGroup) mSenderName.getParent();
int top = getDistanceFromParent(mSenderName, parent) - getDistanceFromParent(
mMessageContainer, parent) + mSenderName.getHeight();
- clipRect = new Rect(0, top, mDisplaySize.x, mDisplaySize.y);
+ int size = Math.max(mDisplaySize.x, mDisplaySize.y);
+ clipRect = new Rect(0, top, size, size);
} else {
clipRect = null;
}
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index df20e639adf0..af9aae3c318d 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -110,7 +110,8 @@ public class MessagingLayout extends FrameLayout {
// We still want to clip, but only on the top, since views can temporarily out of bounds
// during transitions.
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
- Rect rect = new Rect(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels);
+ int size = Math.max(displayMetrics.widthPixels, displayMetrics.heightPixels);
+ Rect rect = new Rect(0, 0, size, size);
mMessagingLinearLayout.setClipBounds(rect);
mTitleView = findViewById(R.id.title);
mAvatarSize = getResources().getDimensionPixelSize(R.dimen.messaging_avatar_size);
diff --git a/core/java/com/android/internal/widget/MessagingTextMessage.java b/core/java/com/android/internal/widget/MessagingTextMessage.java
index 794cc1dc66f7..219116e414f1 100644
--- a/core/java/com/android/internal/widget/MessagingTextMessage.java
+++ b/core/java/com/android/internal/widget/MessagingTextMessage.java
@@ -105,7 +105,7 @@ public class MessagingTextMessage extends ImageFloatingTextView implements Messa
public int getMeasuredType() {
boolean measuredTooSmall = getMeasuredHeight()
< getLayoutHeight() + getPaddingTop() + getPaddingBottom();
- if (measuredTooSmall) {
+ if (measuredTooSmall && getLineCount() <= 1) {
return MEASURED_TOO_SMALL;
} else {
Layout layout = getLayout();
diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java
index 5729b53e98d7..9048f87ef512 100644
--- a/core/java/com/android/internal/widget/NotificationActionListLayout.java
+++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java
@@ -77,7 +77,6 @@ public class NotificationActionListLayout extends LinearLayout {
int otherViews = 0;
int notGoneChildren = 0;
- View lastNotGoneChild = null;
for (int i = 0; i < N; i++) {
View c = getChildAt(i);
if (c instanceof TextView) {
@@ -87,7 +86,6 @@ public class NotificationActionListLayout extends LinearLayout {
}
if (c.getVisibility() != GONE) {
notGoneChildren++;
- lastNotGoneChild = c;
}
}
@@ -107,11 +105,8 @@ public class NotificationActionListLayout extends LinearLayout {
}
}
}
- boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0;
- boolean singleChildCentered = notGoneChildren == 1 && centerAligned;
- boolean needsRegularMeasurement = notGoneChildren > 1 || singleChildCentered;
- if (needsRegularMeasurement && needRebuild) {
+ if (needRebuild) {
rebuildMeasureOrder(textViews, otherViews);
}
@@ -123,7 +118,7 @@ public class NotificationActionListLayout extends LinearLayout {
int usedWidth = 0;
int measuredChildren = 0;
- for (int i = 0; i < N && needsRegularMeasurement; i++) {
+ for (int i = 0; i < N; i++) {
// Measure shortest children first. To avoid measuring twice, we approximate by looking
// at the text length.
View c;
@@ -156,25 +151,6 @@ public class NotificationActionListLayout extends LinearLayout {
measuredChildren++;
}
- // Make sure to measure the last child full-width if we didn't use up the entire width,
- // or we didn't measure yet because there's just one child.
- if (lastNotGoneChild != null && !centerAligned && (constrained && usedWidth < innerWidth
- || notGoneChildren == 1)) {
- MarginLayoutParams lp = (MarginLayoutParams) lastNotGoneChild.getLayoutParams();
- if (notGoneChildren > 1) {
- // Need to make room, since we already measured this once.
- usedWidth -= lastNotGoneChild.getMeasuredWidth() + lp.rightMargin + lp.leftMargin;
- }
-
- int originalWidth = lp.width;
- lp.width = LayoutParams.MATCH_PARENT;
- measureChildWithMargins(lastNotGoneChild, widthMeasureSpec, usedWidth,
- heightMeasureSpec, 0 /* usedHeight */);
- lp.width = originalWidth;
-
- usedWidth += lastNotGoneChild.getMeasuredWidth() + lp.rightMargin + lp.leftMargin;
- }
-
mTotalWidth = usedWidth + mPaddingRight + mPaddingLeft;
setMeasuredDimension(resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec),
resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec));
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index 99d983957075..c15b7ee4fe04 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -205,37 +205,8 @@ static int legacyReadNetworkStatsDetail(std::vector<stats_line>* lines,
return 0;
}
-static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path,
- jint limitUid, jobjectArray limitIfacesObj, jint limitTag,
- jboolean useBpfStats) {
- ScopedUtfChars path8(env, path);
- if (path8.c_str() == NULL) {
- return -1;
- }
-
- std::vector<std::string> limitIfaces;
- if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) {
- int num = env->GetArrayLength(limitIfacesObj);
- for (int i = 0; i < num; i++) {
- jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i);
- ScopedUtfChars string8(env, string);
- if (string8.c_str() != NULL) {
- limitIfaces.push_back(std::string(string8.c_str()));
- }
- }
- }
- std::vector<stats_line> lines;
-
-
- if (useBpfStats) {
- if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0)
- return -1;
- } else {
- if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag,
- limitUid, path8.c_str()) < 0)
- return -1;
- }
-
+static int statsLinesToNetworkStats(JNIEnv* env, jclass clazz, jobject stats,
+ std::vector<stats_line>& lines) {
int size = lines.size();
bool grow = size > env->GetIntField(stats, gNetworkStatsClassInfo.capacity);
@@ -308,14 +279,58 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstr
env->SetObjectField(stats, gNetworkStatsClassInfo.txPackets, txPackets.getJavaArray());
env->SetObjectField(stats, gNetworkStatsClassInfo.operations, operations.getJavaArray());
}
-
return 0;
}
+static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path,
+ jint limitUid, jobjectArray limitIfacesObj, jint limitTag,
+ jboolean useBpfStats) {
+ ScopedUtfChars path8(env, path);
+ if (path8.c_str() == NULL) {
+ return -1;
+ }
+
+ std::vector<std::string> limitIfaces;
+ if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) {
+ int num = env->GetArrayLength(limitIfacesObj);
+ for (int i = 0; i < num; i++) {
+ jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i);
+ ScopedUtfChars string8(env, string);
+ if (string8.c_str() != NULL) {
+ limitIfaces.push_back(std::string(string8.c_str()));
+ }
+ }
+ }
+ std::vector<stats_line> lines;
+
+
+ if (useBpfStats) {
+ if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0)
+ return -1;
+ } else {
+ if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag,
+ limitUid, path8.c_str()) < 0)
+ return -1;
+ }
+
+ return statsLinesToNetworkStats(env, clazz, stats, lines);
+}
+
+static int readNetworkStatsDev(JNIEnv* env, jclass clazz, jobject stats) {
+ std::vector<stats_line> lines;
+
+ if (parseBpfNetworkStatsDev(&lines) < 0)
+ return -1;
+
+ return statsLinesToNetworkStats(env, clazz, stats, lines);
+}
+
static const JNINativeMethod gMethods[] = {
{ "nativeReadNetworkStatsDetail",
"(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;IZ)I",
- (void*) readNetworkStatsDetail }
+ (void*) readNetworkStatsDetail },
+ { "nativeReadNetworkStatsDev", "(Landroid/net/NetworkStats;)I",
+ (void*) readNetworkStatsDev },
};
int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) {
diff --git a/core/proto/android/app/notification_channel.proto b/core/proto/android/app/notification_channel.proto
index 337aa1c20c7a..d3808e890025 100644
--- a/core/proto/android/app/notification_channel.proto
+++ b/core/proto/android/app/notification_channel.proto
@@ -53,4 +53,5 @@ message NotificationChannelProto {
optional android.media.AudioAttributesProto audio_attributes = 16;
// If this is a blockable system notification channel.
optional bool is_blockable_system = 17;
+ optional bool fg_service_shown = 18;
}
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 503bd215af3c..64e1239f36f6 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -161,6 +161,7 @@ message IncidentProto {
optional CpuFreqProto cpu_freq = 2004 [
(section).type = SECTION_FILE,
+ (section).device_specific = true,
(section).args = "/sys/devices/system/cpu/cpufreq/all_time_in_state"
];
@@ -170,7 +171,8 @@ message IncidentProto {
];
optional BatteryTypeProto battery_type = 2006 [
- (section).type = SECTION_NONE, // disabled since the path is device specific!
+ (section).type = SECTION_FILE,
+ (section).device_specific = true,
(section).args = "/sys/class/power_supply/bms/battery_type"
];
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8235507e4528..1f8d43cb8a8c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -840,56 +840,17 @@
android:protectionLevel="dangerous|instant" />
<!-- ====================================================================== -->
- <!-- Permissions for accessing the device telephony -->
+ <!-- Permissions for accessing the call log -->
<!-- ====================================================================== -->
<eat-comment />
<!-- Used for permissions that are associated telephony features. -->
- <permission-group android:name="android.permission-group.PHONE"
+ <permission-group android:name="android.permission-group.CALL_LOG"
android:icon="@drawable/perm_group_phone_calls"
- android:label="@string/permgrouplab_phone"
- android:description="@string/permgroupdesc_phone"
- android:request="@string/permgrouprequest_phone"
- android:priority="500" />
-
- <!-- Allows read only access to phone state, including the phone number of the device,
- current cellular network information, the status of any ongoing calls, and a list of any
- {@link android.telecom.PhoneAccount}s registered on the device.
- <p class="note"><strong>Note:</strong> If <em>both</em> your <a
- href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
- minSdkVersion}</a> and <a
- href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
- targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
- grants your app this permission. If you don't need this permission, be sure your <a
- href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
- targetSdkVersion}</a> is 4 or higher.
- <p>Protection level: dangerous
- -->
- <permission android:name="android.permission.READ_PHONE_STATE"
- android:permissionGroup="android.permission-group.PHONE"
- android:label="@string/permlab_readPhoneState"
- android:description="@string/permdesc_readPhoneState"
- android:protectionLevel="dangerous" />
-
- <!-- Allows read access to the device's phone number(s). This is a subset of the capabilities
- granted by {@link #READ_PHONE_STATE} but is exposed to instant applications.
- <p>Protection level: dangerous-->
- <permission android:name="android.permission.READ_PHONE_NUMBERS"
- android:permissionGroup="android.permission-group.PHONE"
- android:label="@string/permlab_readPhoneNumbers"
- android:description="@string/permdesc_readPhoneNumbers"
- android:protectionLevel="dangerous|instant" />
-
- <!-- Allows an application to initiate a phone call without going through
- the Dialer user interface for the user to confirm the call.
- <p>Protection level: dangerous
- -->
- <permission android:name="android.permission.CALL_PHONE"
- android:permissionGroup="android.permission-group.PHONE"
- android:permissionFlags="costsMoney"
- android:label="@string/permlab_callPhone"
- android:description="@string/permdesc_callPhone"
- android:protectionLevel="dangerous" />
+ android:label="@string/permgrouplab_calllog"
+ android:description="@string/permgroupdesc_calllog"
+ android:request="@string/permgrouprequest_calllog"
+ android:priority="450" />
<!-- Allows an application to access the IMS call service: making and
modifying a call
@@ -897,7 +858,6 @@
@hide
-->
<permission android:name="android.permission.ACCESS_IMS_CALL_SERVICE"
- android:permissionGroup="android.permission-group.PHONE"
android:label="@string/permlab_accessImsCallService"
android:description="@string/permdesc_accessImsCallService"
android:protectionLevel="signature|privileged" />
@@ -915,7 +875,7 @@
<p>Protection level: dangerous
-->
<permission android:name="android.permission.READ_CALL_LOG"
- android:permissionGroup="android.permission-group.PHONE"
+ android:permissionGroup="android.permission-group.CALL_LOG"
android:label="@string/permlab_readCallLog"
android:description="@string/permdesc_readCallLog"
android:protectionLevel="dangerous" />
@@ -934,11 +894,74 @@
<p>Protection level: dangerous
-->
<permission android:name="android.permission.WRITE_CALL_LOG"
- android:permissionGroup="android.permission-group.PHONE"
+ android:permissionGroup="android.permission-group.CALL_LOG"
android:label="@string/permlab_writeCallLog"
android:description="@string/permdesc_writeCallLog"
android:protectionLevel="dangerous" />
+ <!-- Allows an application to see the number being dialed during an outgoing
+ call with the option to redirect the call to a different number or
+ abort the call altogether.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.PROCESS_OUTGOING_CALLS"
+ android:permissionGroup="android.permission-group.CALL_LOG"
+ android:label="@string/permlab_processOutgoingCalls"
+ android:description="@string/permdesc_processOutgoingCalls"
+ android:protectionLevel="dangerous" />
+
+ <!-- ====================================================================== -->
+ <!-- Permissions for accessing the device telephony -->
+ <!-- ====================================================================== -->
+ <eat-comment />
+
+ <!-- Used for permissions that are associated telephony features. -->
+ <permission-group android:name="android.permission-group.PHONE"
+ android:icon="@drawable/perm_group_phone_calls"
+ android:label="@string/permgrouplab_phone"
+ android:description="@string/permgroupdesc_phone"
+ android:request="@string/permgrouprequest_phone"
+ android:priority="500" />
+
+ <!-- Allows read only access to phone state, including the phone number of the device,
+ current cellular network information, the status of any ongoing calls, and a list of any
+ {@link android.telecom.PhoneAccount}s registered on the device.
+ <p class="note"><strong>Note:</strong> If <em>both</em> your <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
+ minSdkVersion}</a> and <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
+ grants your app this permission. If you don't need this permission, be sure your <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> is 4 or higher.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.READ_PHONE_STATE"
+ android:permissionGroup="android.permission-group.PHONE"
+ android:label="@string/permlab_readPhoneState"
+ android:description="@string/permdesc_readPhoneState"
+ android:protectionLevel="dangerous" />
+
+ <!-- Allows read access to the device's phone number(s). This is a subset of the capabilities
+ granted by {@link #READ_PHONE_STATE} but is exposed to instant applications.
+ <p>Protection level: dangerous-->
+ <permission android:name="android.permission.READ_PHONE_NUMBERS"
+ android:permissionGroup="android.permission-group.PHONE"
+ android:label="@string/permlab_readPhoneNumbers"
+ android:description="@string/permdesc_readPhoneNumbers"
+ android:protectionLevel="dangerous|instant" />
+
+ <!-- Allows an application to initiate a phone call without going through
+ the Dialer user interface for the user to confirm the call.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.CALL_PHONE"
+ android:permissionGroup="android.permission-group.PHONE"
+ android:permissionFlags="costsMoney"
+ android:label="@string/permlab_callPhone"
+ android:description="@string/permdesc_callPhone"
+ android:protectionLevel="dangerous" />
+
<!-- Allows an application to add voicemails into the system.
<p>Protection level: dangerous
-->
@@ -957,18 +980,6 @@
android:label="@string/permlab_use_sip"
android:protectionLevel="dangerous"/>
- <!-- Allows an application to see the number being dialed during an outgoing
- call with the option to redirect the call to a different number or
- abort the call altogether.
- <p>Protection level: dangerous
- -->
- <permission android:name="android.permission.PROCESS_OUTGOING_CALLS"
- android:permissionGroup="android.permission-group.PHONE"
- android:label="@string/permlab_processOutgoingCalls"
- android:description="@string/permdesc_processOutgoingCalls"
- android:protectionLevel="dangerous" />
-
-
<!-- Allows the app to answer an incoming phone call.
<p>Protection level: dangerous
-->
@@ -1458,6 +1469,12 @@
<permission android:name="android.permission.MANAGE_WIFI_WHEN_PERMISSION_REVIEW_REQUIRED"
android:protectionLevel="signature" />
+ <!-- #SystemApi @hide Allows an app to bypass Private DNS.
+ <p>Not for use by third-party applications.
+ TODO: publish as system API in next API release. -->
+ <permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"
+ android:protectionLevel="signature" />
+
<!-- ======================================= -->
<!-- Permissions for short range, peripheral networks -->
<!-- ======================================= -->
diff --git a/core/res/res/anim-ldrtl/cross_profile_apps_thumbnail_enter.xml b/core/res/res/anim-ldrtl/cross_profile_apps_thumbnail_enter.xml
new file mode 100644
index 000000000000..6f3dc8c7de0e
--- /dev/null
+++ b/core/res/res/anim-ldrtl/cross_profile_apps_thumbnail_enter.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+<!-- This should be kept in sync with task_open_enter.xml -->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false" android:zAdjustment="top">
+
+ <alpha
+ android:fromAlpha="1"
+ android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/linear"
+ android:startOffset="67"
+ android:duration="217"/>
+
+ <translate
+ android:fromXDelta="-105%"
+ android:toXDelta="0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/aggressive_ease"
+ android:startOffset="50"
+ android:duration="383"/>
+
+ <scale
+ android:fromXScale="1.0526"
+ android:toXScale="1"
+ android:fromYScale="1.0526"
+ android:toYScale="1"
+ android:pivotX="50%"
+ android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="283"/>
+
+ <scale
+ android:fromXScale="0.95"
+ android:toXScale="1"
+ android:fromYScale="0.95"
+ android:toYScale="1"
+ android:pivotX="50%"
+ android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:startOffset="283"
+ android:duration="317"/>
+
+ <!-- To keep the thumbnail around longer and fade out the thumbnail -->
+ <alpha android:fromAlpha="1.0" android:toAlpha="0"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:startOffset="717"
+ android:duration="200"/>
+</set> \ No newline at end of file
diff --git a/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml b/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml
index 6f3dc8c7de0e..4c2559f1e47d 100644
--- a/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml
+++ b/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml
@@ -31,7 +31,7 @@
android:duration="217"/>
<translate
- android:fromXDelta="-105%"
+ android:fromXDelta="105%"
android:toXDelta="0"
android:fillEnabled="true"
android:fillBefore="true"
diff --git a/core/res/res/drawable/ic_dnd_block_notifications.xml b/core/res/res/drawable/ic_dnd_block_notifications.xml
new file mode 100644
index 000000000000..498361455708
--- /dev/null
+++ b/core/res/res/drawable/ic_dnd_block_notifications.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="40dp"
+ android:height="40dp"
+ android:viewportWidth="40.0"
+ android:viewportHeight="40.0">
+ <path
+ android:pathData="M34,20H2c-1.1,0 -2,-0.9 -2,-2V6c0,-1.1 0.9,-2 2,-2h32c1.1,0 2,0.9 2,2v12C36,19.1 35.1,20 34,20z"
+ android:fillColor="#FBBC04"/>
+ <path
+ android:pathData="M4.63,10L4.63,10c-0.83,0 -1.5,-0.67 -1.5,-1.5v0C3.12,7.67 3.8,7 4.62,7h0c0.82,0 1.5,0.67 1.5,1.5v0C6.12,9.33 5.45,10 4.63,10z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M8.62,7.5h9.5v2h-9.5z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M3.12,15h24v2h-24z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M3.12,12h17.5v2h-17.5z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M33.59,6.41m-5.78,0a5.78,5.78 0,1 1,11.56 0a5.78,5.78 0,1 1,-11.56 0"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M33.5,0C29.91,0 27,2.91 27,6.5s2.91,6.5 6.5,6.5S40,10.09 40,6.5S37.09,0 33.5,0zM33.5,11.7c-2.87,0 -5.2,-2.33 -5.2,-5.2s2.33,-5.2 5.2,-5.2s5.2,2.33 5.2,5.2S36.37,11.7 33.5,11.7z"
+ android:fillColor="#4285F4"/>
+ <path
+ android:pathData="M30.25,5.85h6.5v1.3h-6.5z"
+ android:fillColor="#4285F4"/>
+</vector>
diff --git a/core/res/res/layout/magnifier.xml b/core/res/res/layout/magnifier.xml
deleted file mode 100644
index f3344c7470a1..000000000000
--- a/core/res/res/layout/magnifier.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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
- -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/magnifier_inner"
- android:layout_width="@android:dimen/magnifier_width"
- android:layout_height="@android:dimen/magnifier_height"
- android:elevation="@android:dimen/magnifier_elevation"
- android:background="?android:attr/floatingToolbarPopupBackgroundDrawable"
- android:scaleType="fitXY">
- <ImageView
- android:id="@+id/magnifier_image"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- </LinearLayout>
-</LinearLayout>
diff --git a/core/res/res/layout/notification_material_reply_text.xml b/core/res/res/layout/notification_material_reply_text.xml
index dbf2dd008101..71632a206e3c 100644
--- a/core/res/res/layout/notification_material_reply_text.xml
+++ b/core/res/res/layout/notification_material_reply_text.xml
@@ -56,7 +56,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:layout_marginStart="@dimen/notification_content_margin_start"
android:layout_marginEnd="@dimen/notification_content_margin_end">
<TextView
android:id="@+id/notification_material_reply_text_1"
@@ -72,7 +71,6 @@
android:layout_height="@dimen/messaging_group_sending_progress_size"
android:layout_width="@dimen/messaging_group_sending_progress_size"
android:layout_marginStart="@dimen/notification_content_margin_start"
- android:layout_marginEnd="@dimen/notification_content_margin_end"
android:layout_gravity="center"
android:indeterminate="true"
style="?android:attr/progressBarStyleSmall" />
diff --git a/core/res/res/layout/notification_template_messaging_group.xml b/core/res/res/layout/notification_template_messaging_group.xml
index 9bdc495d574e..08f8f5745500 100644
--- a/core/res/res/layout/notification_template_messaging_group.xml
+++ b/core/res/res/layout/notification_template_messaging_group.xml
@@ -42,8 +42,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/notification_text_margin_top"
- android:spacing="2dp"
- android:layout_weight="1"/>
+ android:spacing="2dp"/>
</com.android.internal.widget.RemeasuringLinearLayout>
<FrameLayout
android:id="@+id/messaging_group_icon_container"
diff --git a/core/res/res/values-mcc405/config.xml b/core/res/res/values-mcc405/config.xml
index 6b77e9c1663a..4cadef7893d3 100644
--- a/core/res/res/values-mcc405/config.xml
+++ b/core/res/res/values-mcc405/config.xml
@@ -20,4 +20,6 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Whether camera shutter sound is forced or not (country specific). -->
<bool name="config_camera_sound_forced">true</bool>
+ <!-- Show area update info settings in CellBroadcastReceiver and information in SIM status in Settings app -->
+ <bool name="config_showAreaUpdateInfoSettings">true</bool>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 5c80d4d26563..780cda2fb882 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1836,12 +1836,16 @@
<string name="db_default_sync_mode" translatable="false">FULL</string>
<!-- The database synchronization mode when using Write-Ahead Logging.
- FULL is safest and preserves durability at the cost of extra fsyncs.
- NORMAL sacrifices durability in WAL mode because syncs are only performed before
- and after checkpoint operations. If checkpoints are infrequent and power loss
- occurs, then committed transactions could be lost and applications might break.
+ From https://www.sqlite.org/pragma.html#pragma_synchronous:
+ WAL mode is safe from corruption with synchronous=NORMAL, and probably DELETE mode is safe
+ too on modern filesystems. WAL mode is always consistent with synchronous=NORMAL, but WAL
+ mode does lose durability. A transaction committed in WAL mode with
+ synchronous=NORMAL might roll back following a power loss or system crash.
+ Transactions are durable across application crashes regardless of the synchronous setting
+ or journal mode. The synchronous=NORMAL setting is a good choice for most applications
+ running in WAL mode.
Choices are: FULL, NORMAL, OFF. -->
- <string name="db_wal_sync_mode" translatable="false">FULL</string>
+ <string name="db_wal_sync_mode" translatable="false">NORMAL</string>
<!-- The Write-Ahead Log auto-checkpoint interval in database pages (typically 1 to 4KB).
The log is checkpointed automatically whenever it exceeds this many pages.
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 7ecd9ab8cc42..791f7c68369f 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -247,7 +247,7 @@
<dimen name="notification_header_shrink_min_width">72dp</dimen>
<!-- The minimum height of the content if there are at least two lines or a picture-->
- <dimen name="notification_min_content_height">41dp</dimen>
+ <dimen name="notification_min_content_height">39dp</dimen>
<!-- The size of the media actions in the media notification. -->
<dimen name="media_notification_action_button_size">48dp</dimen>
@@ -632,7 +632,7 @@
<!-- The maximum width of a image in a media notification. The images will be reduced to that width in case they are bigger.-->
<dimen name="notification_media_image_max_width_low_ram">100dp</dimen>
<!-- The size of the right icon image when on low ram -->
- <dimen name="notification_right_icon_size_low_ram">38dp</dimen>
+ <dimen name="notification_right_icon_size_low_ram">@dimen/notification_right_icon_size</dimen>
<dimen name="messaging_avatar_size">@dimen/notification_right_icon_size</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b92052b9ebde..bf7ca524c93e 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -724,6 +724,14 @@
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to take pictures and record video?</string>
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permgrouplab_calllog">Call logs</string>
+ <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permgroupdesc_calllog">read and write phone call log</string>
+ <!-- Message shown to the user when the apps requests permission from this group -->
+ <string name="permgrouprequest_calllog">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access your phone call logs?</string>
+
+ <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgrouplab_phone">Phone</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgroupdesc_phone">make and manage phone calls</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 5298e5b66d5a..5edafecca841 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2555,6 +2555,7 @@
<java-symbol type="drawable" name="ic_storage_48dp" />
<java-symbol type="drawable" name="ic_usb_48dp" />
<java-symbol type="drawable" name="ic_zen_24dp" />
+ <java-symbol type="drawable" name="ic_dnd_block_notifications" />
<!-- Floating toolbar -->
<java-symbol type="id" name="floating_toolbar_menu_item_image" />
@@ -2586,9 +2587,6 @@
<java-symbol type="attr" name="floatingToolbarDividerColor" />
<!-- Magnifier -->
- <java-symbol type="id" name="magnifier_image" />
- <java-symbol type="id" name="magnifier_inner" />
- <java-symbol type="layout" name="magnifier" />
<java-symbol type="dimen" name="magnifier_width" />
<java-symbol type="dimen" name="magnifier_height" />
<java-symbol type="dimen" name="magnifier_elevation" />
diff --git a/core/res/res/xml/default_zen_mode_config.xml b/core/res/res/xml/default_zen_mode_config.xml
index 3a7185105c48..ba8173e9e012 100644
--- a/core/res/res/xml/default_zen_mode_config.xml
+++ b/core/res/res/xml/default_zen_mode_config.xml
@@ -19,7 +19,7 @@
<!-- Default configuration for zen mode. See android.service.notification.ZenModeConfig. -->
<zen version="7">
- <allow alarms="true" media="true" system="false" calls="false" messages="false"
+ <allow alarms="true" media="true" system="false" calls="false" callsFrom="2" messages="false"
reminders="false" events="false" />
<!-- all visual effects that exist as of P -->
diff --git a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
index bf91a16cb3b7..6d5276f2423e 100644
--- a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
+++ b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
@@ -118,7 +118,7 @@ public class InstallOverlayTests extends BaseHostJUnit4Test {
@Test
public void installPlatformSignedFrameworkOverlayAndUpdate() throws Exception {
- assertTrue(runDeviceTests(DEVICE_TEST_PKG, DEVICE_TEST_CLS, "expectAppResource"));
+ assertTrue(runDeviceTests(DEVICE_TEST_PKG, DEVICE_TEST_CLS, "expectFrameworkResource"));
installPackage("OverlayHostTests_FrameworkOverlayV1.apk");
setOverlayEnabled(FRAMEWORK_OVERLAY_PACKAGE_NAME, true);
@@ -138,6 +138,27 @@ public class InstallOverlayTests extends BaseHostJUnit4Test {
"expectFrameworkOverlayV2Resource"));
}
+ @Test
+ public void enabledFrameworkOverlayMustAffectNewlyInstalledPackage() throws Exception {
+ try {
+ setPackageEnabled(DEVICE_TEST_PKG, false);
+
+ installPackage("OverlayHostTests_FrameworkOverlayV1.apk");
+ setOverlayEnabled(FRAMEWORK_OVERLAY_PACKAGE_NAME, true);
+ assertTrue(overlayManagerContainsPackage(FRAMEWORK_OVERLAY_PACKAGE_NAME));
+
+ setPackageEnabled(DEVICE_TEST_PKG, true);
+ assertTrue(runDeviceTests(DEVICE_TEST_PKG, DEVICE_TEST_CLS,
+ "expectFrameworkOverlayV1Resource"));
+ } finally {
+ setPackageEnabled(DEVICE_TEST_PKG, true);
+ }
+ }
+
+ private void setPackageEnabled(String pkg, boolean enabled) throws Exception {
+ getDevice().executeShellCommand("cmd package " + (enabled ? "enable " : "disable ") + pkg);
+ }
+
private void setOverlayEnabled(String pkg, boolean enabled) throws Exception {
getDevice().executeShellCommand("cmd overlay " + (enabled ? "enable " : "disable ") + pkg);
}
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/src/com/android/server/om/hosttest/update_overlay_test/UpdateOverlayTest.java b/core/tests/overlaytests/host/test-apps/UpdateOverlay/src/com/android/server/om/hosttest/update_overlay_test/UpdateOverlayTest.java
index d46bb378971d..a174d774b80e 100644
--- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/src/com/android/server/om/hosttest/update_overlay_test/UpdateOverlayTest.java
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/src/com/android/server/om/hosttest/update_overlay_test/UpdateOverlayTest.java
@@ -61,7 +61,7 @@ public class UpdateOverlayTest {
}
@Test
- public void expectFrameworkOverlayResource() throws Exception {
+ public void expectFrameworkResource() throws Exception {
assertEquals("OK", mResources.getString(android.R.string.ok));
}
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index be7d663b412f..569de76f294e 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -40,7 +40,6 @@ DeferredLayerUpdater::DeferredLayerUpdater(RenderState& renderState, CreateLayer
}
DeferredLayerUpdater::~DeferredLayerUpdater() {
- SkSafeUnref(mColorFilter);
setTransform(nullptr);
mRenderState.unregisterDeferredLayerUpdater(this);
destroyLayer();
@@ -67,8 +66,11 @@ void DeferredLayerUpdater::destroyLayer() {
void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
mAlpha = PaintUtils::getAlphaDirect(paint);
mMode = PaintUtils::getBlendModeDirect(paint);
- SkColorFilter* colorFilter = (paint) ? paint->getColorFilter() : nullptr;
- SkRefCnt_SafeAssign(mColorFilter, colorFilter);
+ if (paint) {
+ mColorFilter = paint->refColorFilter();
+ } else {
+ mColorFilter.reset();
+ }
}
void DeferredLayerUpdater::apply() {
@@ -143,7 +145,7 @@ void DeferredLayerUpdater::doUpdateTexImage() {
#endif
mSurfaceTexture->getTransformMatrix(transform);
- updateLayer(forceFilter, transform);
+ updateLayer(forceFilter, transform, mSurfaceTexture->getCurrentDataSpace());
}
}
@@ -153,17 +155,19 @@ void DeferredLayerUpdater::doUpdateVkTexImage() {
Layer::Api::OpenGL, Layer::Api::Vulkan);
static const mat4 identityMatrix;
- updateLayer(false, identityMatrix.data);
+ updateLayer(false, identityMatrix.data, HAL_DATASPACE_UNKNOWN);
VkLayer* vkLayer = static_cast<VkLayer*>(mLayer);
vkLayer->updateTexture();
}
-void DeferredLayerUpdater::updateLayer(bool forceFilter, const float* textureTransform) {
+void DeferredLayerUpdater::updateLayer(bool forceFilter, const float* textureTransform,
+ android_dataspace dataspace) {
mLayer->setBlend(mBlend);
mLayer->setForceFilter(forceFilter);
mLayer->setSize(mWidth, mHeight);
mLayer->getTexTransform().load(textureTransform);
+ mLayer->setDataSpace(dataspace);
}
void DeferredLayerUpdater::detachSurfaceTexture() {
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 9dc029fd3852..fe3ee7a2b4c6 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -20,6 +20,7 @@
#include <SkMatrix.h>
#include <cutils/compiler.h>
#include <gui/GLConsumer.h>
+#include <system/graphics.h>
#include <utils/StrongPointer.h>
#include <GLES2/gl2.h>
@@ -41,7 +42,7 @@ public:
// Note that DeferredLayerUpdater assumes it is taking ownership of the layer
// and will not call incrementRef on it as a result.
typedef std::function<Layer*(RenderState& renderState, uint32_t layerWidth,
- uint32_t layerHeight, SkColorFilter* colorFilter, int alpha,
+ uint32_t layerHeight, sk_sp<SkColorFilter> colorFilter, int alpha,
SkBlendMode mode, bool blend)>
CreateLayerFn;
ANDROID_API explicit DeferredLayerUpdater(RenderState& renderState, CreateLayerFn createLayerFn,
@@ -96,7 +97,7 @@ public:
void detachSurfaceTexture();
- void updateLayer(bool forceFilter, const float* textureTransform);
+ void updateLayer(bool forceFilter, const float* textureTransform, android_dataspace dataspace);
void destroyLayer();
@@ -109,7 +110,7 @@ private:
int mWidth = 0;
int mHeight = 0;
bool mBlend = false;
- SkColorFilter* mColorFilter = nullptr;
+ sk_sp<SkColorFilter> mColorFilter;
int mAlpha = 255;
SkBlendMode mMode = SkBlendMode::kSrcOver;
sp<GLConsumer> mSurfaceTexture;
diff --git a/libs/hwui/GlLayer.cpp b/libs/hwui/GlLayer.cpp
index 32a30149e476..42ae29d76898 100644
--- a/libs/hwui/GlLayer.cpp
+++ b/libs/hwui/GlLayer.cpp
@@ -32,7 +32,7 @@ namespace android {
namespace uirenderer {
GlLayer::GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend)
+ sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend)
: Layer(renderState, Api::OpenGL, colorFilter, alpha, mode)
, caches(Caches::getInstance())
, texture(caches) {
diff --git a/libs/hwui/GlLayer.h b/libs/hwui/GlLayer.h
index 1b091914f318..28749a0d125c 100644
--- a/libs/hwui/GlLayer.h
+++ b/libs/hwui/GlLayer.h
@@ -32,7 +32,7 @@ class Caches;
class GlLayer : public Layer {
public:
GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend);
+ sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend);
virtual ~GlLayer();
uint32_t getWidth() const override { return texture.mWidth; }
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 86950d5ebb10..fb8f0337c95e 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -18,34 +18,58 @@
#include "renderstate/RenderState.h"
-#include <SkColorFilter.h>
+#include <SkToSRGBColorFilter.h>
namespace android {
namespace uirenderer {
-Layer::Layer(RenderState& renderState, Api api, SkColorFilter* colorFilter, int alpha,
+Layer::Layer(RenderState& renderState, Api api, sk_sp<SkColorFilter> colorFilter, int alpha,
SkBlendMode mode)
: GpuMemoryTracker(GpuObjectType::Layer)
, mRenderState(renderState)
, mApi(api)
- , colorFilter(nullptr)
+ , mColorFilter(colorFilter)
, alpha(alpha)
, mode(mode) {
// TODO: This is a violation of Android's typical ref counting, but it
// preserves the old inc/dec ref locations. This should be changed...
incStrong(nullptr);
-
+ buildColorSpaceWithFilter();
renderState.registerLayer(this);
}
Layer::~Layer() {
- SkSafeUnref(colorFilter);
-
mRenderState.unregisterLayer(this);
}
-void Layer::setColorFilter(SkColorFilter* filter) {
- SkRefCnt_SafeAssign(colorFilter, filter);
+void Layer::setColorFilter(sk_sp<SkColorFilter> filter) {
+ if (filter != mColorFilter) {
+ mColorFilter = filter;
+ buildColorSpaceWithFilter();
+ }
+}
+
+void Layer::setDataSpace(android_dataspace dataspace) {
+ if (dataspace != mCurrentDataspace) {
+ mCurrentDataspace = dataspace;
+ buildColorSpaceWithFilter();
+ }
+}
+
+void Layer::buildColorSpaceWithFilter() {
+ sk_sp<SkColorFilter> colorSpaceFilter;
+ sk_sp<SkColorSpace> colorSpace = DataSpaceToColorSpace(mCurrentDataspace);
+ if (colorSpace && !colorSpace->isSRGB()) {
+ colorSpaceFilter = SkToSRGBColorFilter::Make(colorSpace);
+ }
+
+ if (mColorFilter && colorSpaceFilter) {
+ mColorSpaceWithFilter = mColorFilter->makeComposed(colorSpaceFilter);
+ } else if (colorSpaceFilter) {
+ mColorSpaceWithFilter = colorSpaceFilter;
+ } else {
+ mColorSpaceWithFilter = mColorFilter;
+ }
}
void Layer::postDecStrong() {
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 69213817f8af..89bcddcc96d0 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -19,6 +19,8 @@
#include <GpuMemoryTracker.h>
#include <utils/RefBase.h>
+#include <SkColorFilter.h>
+#include <SkColorSpace.h>
#include <SkBlendMode.h>
#include <SkPaint.h>
@@ -72,9 +74,15 @@ public:
inline SkBlendMode getMode() const { return mode; }
- inline SkColorFilter* getColorFilter() const { return colorFilter; }
+ inline SkColorFilter* getColorFilter() const { return mColorFilter.get(); }
- void setColorFilter(SkColorFilter* filter);
+ void setColorFilter(sk_sp<SkColorFilter> filter);
+
+ void setDataSpace(android_dataspace dataspace);
+
+ void setColorSpace(sk_sp<SkColorSpace> colorSpace);
+
+ inline sk_sp<SkColorFilter> getColorSpaceWithFilter() const { return mColorSpaceWithFilter; }
inline mat4& getTexTransform() { return texTransform; }
@@ -87,18 +95,30 @@ public:
void postDecStrong();
protected:
- Layer(RenderState& renderState, Api api, SkColorFilter* colorFilter, int alpha,
+ Layer(RenderState& renderState, Api api, sk_sp<SkColorFilter>, int alpha,
SkBlendMode mode);
RenderState& mRenderState;
private:
+ void buildColorSpaceWithFilter();
+
Api mApi;
/**
* Color filter used to draw this layer. Optional.
*/
- SkColorFilter* colorFilter;
+ sk_sp<SkColorFilter> mColorFilter;
+
+ /**
+ * Colorspace of the contents of the layer. Optional.
+ */
+ android_dataspace mCurrentDataspace = HAL_DATASPACE_UNKNOWN;
+
+ /**
+ * A color filter that is the combination of the mColorFilter and mColorSpace. Optional.
+ */
+ sk_sp<SkColorFilter> mColorSpaceWithFilter;
/**
* Indicates raster data backing the layer is scaled, requiring filtration.
diff --git a/libs/hwui/VkLayer.h b/libs/hwui/VkLayer.h
index f23f4726017e..e9664d04b7a5 100644
--- a/libs/hwui/VkLayer.h
+++ b/libs/hwui/VkLayer.h
@@ -28,7 +28,7 @@ namespace uirenderer {
class VkLayer : public Layer {
public:
VkLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend)
+ sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend)
: Layer(renderState, Api::Vulkan, colorFilter, alpha, mode)
, mWidth(layerWidth)
, mHeight(layerHeight)
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index 293e45f2273f..4f16ddb9881b 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -51,8 +51,13 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer
GrGLTextureInfo externalTexture;
externalTexture.fTarget = glLayer->getRenderTarget();
externalTexture.fID = glLayer->getTextureId();
- GrBackendTexture backendTexture(layerWidth, layerHeight, kRGBA_8888_GrPixelConfig,
- externalTexture);
+ // The format may not be GL_RGBA8, but given the DeferredLayerUpdater and GLConsumer don't
+ // expose that info we use it as our default. Further, given that we only use this texture
+ // as a source this will not impact how Skia uses the texture. The only potential affect
+ // this is anticipated to have is that for some format types if we are not bound as an OES
+ // texture we may get invalid results for SKP capture if we read back the texture.
+ externalTexture.fFormat = GL_RGBA8;
+ GrBackendTexture backendTexture(layerWidth, layerHeight, GrMipMapped::kNo, externalTexture);
layerImage = SkImage::MakeFromTexture(context, backendTexture, kTopLeft_GrSurfaceOrigin,
kPremul_SkAlphaType, nullptr);
} else {
@@ -82,7 +87,7 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer
SkPaint paint;
paint.setAlpha(layer->getAlpha());
paint.setBlendMode(layer->getMode());
- paint.setColorFilter(sk_ref_sp(layer->getColorFilter()));
+ paint.setColorFilter(layer->getColorSpaceWithFilter());
const bool nonIdentityMatrix = !matrix.isIdentity();
if (nonIdentityMatrix) {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 74cfb2854e62..d732a46e6ee4 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -152,7 +152,7 @@ bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBi
}
static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+ sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend) {
GlLayer* layer =
new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
layer->generateTexture();
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 9e7304678021..d66cba12ad99 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -147,6 +147,7 @@ void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque,
GrContext* currentContext = layerNode->getLayerSurface()->getCanvas()->getGrContext();
if (cachedContext.get() != currentContext) {
if (cachedContext.get()) {
+ ATRACE_NAME("flush layers (context changed)");
cachedContext->flush();
}
cachedContext.reset(SkSafeRef(currentContext));
@@ -155,6 +156,7 @@ void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque,
}
if (cachedContext.get()) {
+ ATRACE_NAME("flush layers");
cachedContext->flush();
}
}
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 653007482c0a..5825060f902a 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -115,7 +115,8 @@ bool SkiaVulkanPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bi
}
static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+ sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode,
+ bool blend) {
return new VkLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
}
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index 876af47e256f..f96001ebdd57 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -123,7 +123,8 @@ bool OpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap
}
static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+ sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode,
+ bool blend) {
GlLayer* layer =
new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
Caches::getInstance().textureState().activateTexture(0);
diff --git a/libs/hwui/tests/common/TestListViewSceneBase.cpp b/libs/hwui/tests/common/TestListViewSceneBase.cpp
index a7f4d4d3991f..fd331333d38a 100644
--- a/libs/hwui/tests/common/TestListViewSceneBase.cpp
+++ b/libs/hwui/tests/common/TestListViewSceneBase.cpp
@@ -57,7 +57,8 @@ void TestListViewSceneBase::doFrame(int frameNr) {
int pxOffset = -(scrollPx % (mItemSpacing + mItemHeight));
std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
- mListView->stagingProperties().getWidth(), mListView->stagingProperties().getHeight()));
+ mListView->stagingProperties().getWidth(), mListView->stagingProperties().getHeight(),
+ mListView.get()));
for (size_t ci = 0; ci < mListItems.size(); ci++) {
// update item position
auto listItem = mListItems[(ci + itemIndexOffset) % mListItems.size()];
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index b99854e5af07..02ac97e0ed5c 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -75,7 +75,7 @@ sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater(
layerUpdater->setTransform(&transform);
// updateLayer so it's ready to draw
- layerUpdater->updateLayer(true, Matrix4::identity().data);
+ layerUpdater->updateLayer(true, Matrix4::identity().data, HAL_DATASPACE_UNKNOWN);
if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
static_cast<GlLayer*>(layerUpdater->backingLayer())
->setRenderTarget(GL_TEXTURE_EXTERNAL_OES);
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 1bfa046eff63..2752ae9a8036 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -250,7 +250,8 @@ public:
static void recordNode(RenderNode& node, std::function<void(Canvas&)> contentCallback) {
std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
- node.stagingProperties().getWidth(), node.stagingProperties().getHeight()));
+ node.stagingProperties().getWidth(), node.stagingProperties().getHeight(),
+ &node));
contentCallback(*canvas.get());
node.setStagingDisplayList(canvas->finishRecording());
}
diff --git a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
index 38999cb1d2ec..f0a5e9dff1b9 100644
--- a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
@@ -44,7 +44,8 @@ public:
std::unique_ptr<Canvas> canvas(
Canvas::create_recording_canvas(container->stagingProperties().getWidth(),
- container->stagingProperties().getHeight()));
+ container->stagingProperties().getHeight(),
+ container.get()));
Paint paint;
paint.setAntiAlias(true);
diff --git a/libs/hwui/tests/common/scenes/TvApp.cpp b/libs/hwui/tests/common/scenes/TvApp.cpp
index 003d8e92fd9f..a64e8444a9b1 100644
--- a/libs/hwui/tests/common/scenes/TvApp.cpp
+++ b/libs/hwui/tests/common/scenes/TvApp.cpp
@@ -194,7 +194,8 @@ private:
// re-recording card's canvas, not necessary but to add some burden to CPU
std::unique_ptr<Canvas> cardcanvas(Canvas::create_recording_canvas(
- card->stagingProperties().getWidth(), card->stagingProperties().getHeight()));
+ card->stagingProperties().getWidth(), card->stagingProperties().getHeight(),
+ card.get()));
sp<RenderNode> image = mImages[ci];
sp<RenderNode> infoArea = mInfoAreas[ci];
cardcanvas->drawRenderNode(infoArea.get());
@@ -205,14 +206,16 @@ private:
sp<RenderNode> overlay = mOverlays[ci];
std::unique_ptr<Canvas> canvas(
Canvas::create_recording_canvas(overlay->stagingProperties().getWidth(),
- overlay->stagingProperties().getHeight()));
+ overlay->stagingProperties().getHeight(),
+ overlay.get()));
canvas->drawColor((curFrame % 150) << 24, SkBlendMode::kSrcOver);
overlay->setStagingDisplayList(canvas->finishRecording());
cardcanvas->drawRenderNode(overlay.get());
} else {
// re-recording image node's canvas, animating ColorFilter
std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
- image->stagingProperties().getWidth(), image->stagingProperties().getHeight()));
+ image->stagingProperties().getWidth(), image->stagingProperties().getHeight(),
+ image.get()));
SkPaint paint;
sk_sp<SkColorFilter> filter(
SkColorFilter::MakeModeFilter((curFrame % 150) << 24, SkBlendMode::kSrcATop));
diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
index b8b5050faa11..f29830f0e34b 100644
--- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
+++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
@@ -44,7 +44,7 @@ RENDERTHREAD_TEST(DeferredLayerUpdater, updateLayer) {
// push the deferred updates to the layer
Matrix4 scaledMatrix;
scaledMatrix.loadScale(0.5, 0.5, 0.0);
- layerUpdater->updateLayer(true, scaledMatrix.data);
+ layerUpdater->updateLayer(true, scaledMatrix.data, HAL_DATASPACE_UNKNOWN);
if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
glLayer->setRenderTarget(GL_TEXTURE_EXTERNAL_OES);
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index c2af867657bf..75740e8b5baf 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -16,6 +16,8 @@
#include "Color.h"
+
+#include <utils/Log.h>
#include <cmath>
namespace android {
@@ -53,5 +55,57 @@ bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace) {
return false;
}
+sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
+
+ SkColorSpace::Gamut gamut;
+ switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
+ case HAL_DATASPACE_STANDARD_BT709:
+ gamut = SkColorSpace::kSRGB_Gamut;
+ break;
+ case HAL_DATASPACE_STANDARD_BT2020:
+ gamut = SkColorSpace::kRec2020_Gamut;
+ break;
+ case HAL_DATASPACE_STANDARD_DCI_P3:
+ gamut = SkColorSpace::kDCIP3_D65_Gamut;
+ break;
+ case HAL_DATASPACE_STANDARD_ADOBE_RGB:
+ gamut = SkColorSpace::kAdobeRGB_Gamut;
+ break;
+ case HAL_DATASPACE_STANDARD_UNSPECIFIED:
+ return nullptr;
+ case HAL_DATASPACE_STANDARD_BT601_625:
+ case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
+ case HAL_DATASPACE_STANDARD_BT601_525:
+ case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
+ case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
+ case HAL_DATASPACE_STANDARD_BT470M:
+ case HAL_DATASPACE_STANDARD_FILM:
+ default:
+ ALOGW("Unsupported Gamut: %d", dataspace);
+ return nullptr;
+ }
+
+ switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
+ case HAL_DATASPACE_TRANSFER_LINEAR:
+ return SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, gamut);
+ case HAL_DATASPACE_TRANSFER_SRGB:
+ return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, gamut);
+ case HAL_DATASPACE_TRANSFER_GAMMA2_2:
+ return SkColorSpace::MakeRGB({2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
+ case HAL_DATASPACE_TRANSFER_GAMMA2_6:
+ return SkColorSpace::MakeRGB({2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
+ case HAL_DATASPACE_TRANSFER_GAMMA2_8:
+ return SkColorSpace::MakeRGB({2.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
+ case HAL_DATASPACE_TRANSFER_UNSPECIFIED:
+ return nullptr;
+ case HAL_DATASPACE_TRANSFER_SMPTE_170M:
+ case HAL_DATASPACE_TRANSFER_ST2084:
+ case HAL_DATASPACE_TRANSFER_HLG:
+ default:
+ ALOGW("Unsupported Gamma: %d", dataspace);
+ return nullptr;
+ }
+}
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index 7ac0d963732f..2bec1f5f7852 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -17,6 +17,7 @@
#define COLOR_H
#include <math.h>
+#include <system/graphics.h>
#include <SkColor.h>
#include <SkColorSpace.h>
@@ -111,6 +112,8 @@ static constexpr float EOCF(float srgb) {
// approximated with the native sRGB transfer function. This method
// returns true for sRGB, gamma 2.2 and Display P3 for instance
bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace);
+
+sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace);
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/incident/proto/android/section.proto b/libs/incident/proto/android/section.proto
index b3ed393394d4..e8280ed690f6 100644
--- a/libs/incident/proto/android/section.proto
+++ b/libs/incident/proto/android/section.proto
@@ -51,6 +51,7 @@ enum SectionType {
message SectionFlags {
optional SectionType type = 1 [default = SECTION_NONE];
optional string args = 2;
+ optional bool device_specific = 3 [default = false];
}
extend google.protobuf.FieldOptions {
diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml
index 5fc9627e39c9..72e37ed4756e 100644
--- a/packages/CaptivePortalLogin/AndroidManifest.xml
+++ b/packages/CaptivePortalLogin/AndroidManifest.xml
@@ -23,6 +23,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />
+ <uses-permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS" />
<application android:label="@string/app_name"
android:usesCleartextTraffic="true">
diff --git a/packages/CarrierDefaultApp/AndroidManifest.xml b/packages/CarrierDefaultApp/AndroidManifest.xml
index 824d9f45c21e..4d9aaecb4092 100644
--- a/packages/CarrierDefaultApp/AndroidManifest.xml
+++ b/packages/CarrierDefaultApp/AndroidManifest.xml
@@ -25,6 +25,7 @@
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
<uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
+ <uses-permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS" />
<uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
<application
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
index 7479d9aa773b..b1933373a8e6 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
@@ -111,13 +111,11 @@ public class CaptivePortalLoginActivity extends Activity {
mWebView.setWebViewClient(mWebViewClient);
mWebView.setWebChromeClient(new MyWebChromeClient());
- mNetwork = getNetworkForCaptivePortal();
- if (mNetwork == null) {
+ final Network network = getNetworkForCaptivePortal();
+ if (network == null) {
requestNetworkForCaptivePortal();
} else {
- mCm.bindProcessToNetwork(mNetwork);
- mCm.setProcessDefaultNetworkForHostResolution(
- ResolvUtil.getNetworkWithUseLocalNameserversFlag(mNetwork));
+ setNetwork(network);
// Start initial page load so WebView finishes loading proxy settings.
// Actual load of mUrl is initiated by MyWebViewClient.
mWebView.loadData("", "text/html", null);
@@ -159,6 +157,15 @@ public class CaptivePortalLoginActivity extends Activity {
super.onDestroy();
}
+ private void setNetwork(Network network) {
+ if (network != null) {
+ mCm.bindProcessToNetwork(network);
+ mCm.setProcessDefaultNetworkForHostResolution(
+ ResolvUtil.getNetworkWithUseLocalNameserversFlag(network));
+ }
+ mNetwork = network;
+ }
+
// Find WebView's proxy BroadcastReceiver and prompt it to read proxy system properties.
private void setWebViewProxy() {
LoadedApk loadedApk = getApplication().mLoadedApk;
@@ -235,6 +242,7 @@ public class CaptivePortalLoginActivity extends Activity {
private void testForCaptivePortal() {
mTestingThread = new Thread(new Runnable() {
public void run() {
+ final Network network = ResolvUtil.makeNetworkWithPrivateDnsBypass(mNetwork);
// Give time for captive portal to open.
try {
Thread.sleep(1000);
@@ -245,7 +253,7 @@ public class CaptivePortalLoginActivity extends Activity {
int httpResponseCode = 500;
int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE);
try {
- urlConnection = (HttpURLConnection) mNetwork.openConnection(
+ urlConnection = (HttpURLConnection) network.openConnection(
new URL(mCm.getCaptivePortalServerUrl()));
urlConnection.setInstanceFollowRedirects(false);
urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
@@ -292,8 +300,7 @@ public class CaptivePortalLoginActivity extends Activity {
@Override
public void onAvailable(Network network) {
if (DBG) logd("Network available: " + network);
- mCm.bindProcessToNetwork(network);
- mNetwork = network;
+ setNetwork(network);
runOnUiThreadIfNotFinishing(() -> {
if (mReload) {
mWebView.reload();
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 2a82fc9b28df..0a720a5b234e 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -38,6 +38,9 @@ import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Path;
import android.provider.DocumentsContract.Root;
import android.provider.Settings;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.DebugUtils;
@@ -360,14 +363,19 @@ public class ExternalStorageProvider extends FileSystemProvider {
@Override
protected File getFileForDocId(String docId, boolean visible) throws FileNotFoundException {
+ return getFileForDocId(docId, visible, true);
+ }
+
+ private File getFileForDocId(String docId, boolean visible, boolean mustExist)
+ throws FileNotFoundException {
RootInfo root = getRootFromDocId(docId);
- return buildFile(root, docId, visible);
+ return buildFile(root, docId, visible, mustExist);
}
private Pair<RootInfo, File> resolveDocId(String docId, boolean visible)
throws FileNotFoundException {
RootInfo root = getRootFromDocId(docId);
- return Pair.create(root, buildFile(root, docId, visible));
+ return Pair.create(root, buildFile(root, docId, visible, true));
}
private RootInfo getRootFromDocId(String docId) throws FileNotFoundException {
@@ -385,7 +393,7 @@ public class ExternalStorageProvider extends FileSystemProvider {
return root;
}
- private File buildFile(RootInfo root, String docId, boolean visible)
+ private File buildFile(RootInfo root, String docId, boolean visible, boolean mustExist)
throws FileNotFoundException {
final int splitIndex = docId.indexOf(':', 1);
final String path = docId.substring(splitIndex + 1);
@@ -398,7 +406,7 @@ public class ExternalStorageProvider extends FileSystemProvider {
target.mkdirs();
}
target = new File(target, path);
- if (!target.exists()) {
+ if (mustExist && !target.exists()) {
throw new FileNotFoundException("Missing file for " + docId + " at " + target);
}
return target;
@@ -410,6 +418,19 @@ public class ExternalStorageProvider extends FileSystemProvider {
}
@Override
+ protected void onDocIdChanged(String docId) {
+ try {
+ // Touch the visible path to ensure that any sdcardfs caches have
+ // been updated to reflect underlying changes on disk.
+ final File visiblePath = getFileForDocId(docId, true, false);
+ if (visiblePath != null) {
+ Os.access(visiblePath.getAbsolutePath(), OsConstants.F_OK);
+ }
+ } catch (FileNotFoundException | ErrnoException ignored) {
+ }
+ }
+
+ @Override
public Cursor queryRoots(String[] projection) throws FileNotFoundException {
final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
synchronized (mRootsLock) {
diff --git a/packages/Osu/Android.mk b/packages/Osu/Android.mk
deleted file mode 100644
index 63c7578b0163..000000000000
--- a/packages/Osu/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SRC_FILES += \
- src/com/android/hotspot2/app/IOSUAccessor.aidl \
- src/com/android/hotspot2/flow/IFlowService.aidl
-
-LOCAL_JAVA_LIBRARIES := telephony-common ims-common bouncycastle conscrypt
-
-LOCAL_PACKAGE_NAME := Osu
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
-
-include $(BUILD_PACKAGE)
-
-########################
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/Osu/AndroidManifest.xml b/packages/Osu/AndroidManifest.xml
deleted file mode 100644
index b804739f5e42..000000000000
--- a/packages/Osu/AndroidManifest.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?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");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.hotspot2">
- <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
- <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
- <uses-permission android:name="android.permission.READ_WIFI_CREDENTIAL" />
- <uses-permission android:name="android.permission.READ_PHONE_STATE" />
- <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
- <uses-permission android:name="android.permission.INTERNET" />
-
- <application
- android:enabled="true"
- android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:supportsRtl="true">
- <activity android:name="com.android.hotspot2.app.MainActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- <intent-filter>
- <action android:name="com.android.hotspot2.OSU_NOTIFICATION" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
- <activity android:name="com.android.hotspot2.osu.OSUWebView">
- </activity>
- <service android:name=".app.OSUService" android:directBootAware="true">
- </service>
- <service android:name=".flow.FlowService" android:process=":osuflow">
- </service>
- </application>
-
-</manifest>
diff --git a/packages/Osu/res/layout/activity_main.xml b/packages/Osu/res/layout/activity_main.xml
deleted file mode 100644
index 7e335377dc11..000000000000
--- a/packages/Osu/res/layout/activity_main.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <TextView
- android:id="@+id/no_osu"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/no_osu"/>
- <ListView
- android:id="@+id/profile_list"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:divider="#1F000000"
- android:dividerHeight="1dp"
- android:padding="16dp" />
-
-</LinearLayout>
diff --git a/packages/Osu/res/layout/list_item.xml b/packages/Osu/res/layout/list_item.xml
deleted file mode 100644
index eb431d39b517..000000000000
--- a/packages/Osu/res/layout/list_item.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
- android:gravity="top"
- android:layout_marginTop="10sp"
- android:layout_marginBottom="10sp"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <ImageView
- android:id="@+id/profile_logo"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
- <LinearLayout
- android:orientation="vertical"
- android:layout_weight="1"
- android:layout_width="0dp"
- android:layout_height="wrap_content">
-
- <TextView
- android:id="@+id/profile_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="20sp"/>
-
- <TextView
- android:id="@+id/profile_detail"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="10sp"
- android:textSize="12sp"/>
-
- </LinearLayout>
-
-</LinearLayout>
diff --git a/packages/Osu/res/layout/osu_web_view.xml b/packages/Osu/res/layout/osu_web_view.xml
deleted file mode 100644
index 4eafb39d1713..000000000000
--- a/packages/Osu/res/layout/osu_web_view.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/container"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <WebView
- android:id="@+id/webview"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_alignParentBottom="true"
- android:layout_alignParentRight="true" />
-
-</FrameLayout>
diff --git a/packages/Osu/res/mipmap-hdpi/ic_launcher.png b/packages/Osu/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index cde69bcccec6..000000000000
--- a/packages/Osu/res/mipmap-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/packages/Osu/res/mipmap-mdpi/ic_launcher.png b/packages/Osu/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index c133a0cbd379..000000000000
--- a/packages/Osu/res/mipmap-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/packages/Osu/res/mipmap-xhdpi/ic_launcher.png b/packages/Osu/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index bfa42f0e7b91..000000000000
--- a/packages/Osu/res/mipmap-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/packages/Osu/res/mipmap-xxhdpi/ic_launcher.png b/packages/Osu/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 324e72cdd748..000000000000
--- a/packages/Osu/res/mipmap-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/packages/Osu/res/mipmap-xxxhdpi/ic_launcher.png b/packages/Osu/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index aee44e138434..000000000000
--- a/packages/Osu/res/mipmap-xxxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/packages/Osu/res/values-w820dp/dimens.xml b/packages/Osu/res/values-w820dp/dimens.xml
deleted file mode 100644
index 63fc81644461..000000000000
--- a/packages/Osu/res/values-w820dp/dimens.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<resources>
- <!-- Example customization of dimensions originally defined in res/values/dimens.xml
- (such as screen margins) for screens with more than 820dp of available width. This
- would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
- <dimen name="activity_horizontal_margin">64dp</dimen>
-</resources>
diff --git a/packages/Osu/res/values/colors.xml b/packages/Osu/res/values/colors.xml
deleted file mode 100644
index 3ab3e9cbce07..000000000000
--- a/packages/Osu/res/values/colors.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <color name="colorPrimary">#3F51B5</color>
- <color name="colorPrimaryDark">#303F9F</color>
- <color name="colorAccent">#FF4081</color>
-</resources>
diff --git a/packages/Osu/res/values/dimens.xml b/packages/Osu/res/values/dimens.xml
deleted file mode 100644
index 47c82246738c..000000000000
--- a/packages/Osu/res/values/dimens.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<resources>
- <!-- Default screen margins, per the Android Design guidelines. -->
- <dimen name="activity_horizontal_margin">16dp</dimen>
- <dimen name="activity_vertical_margin">16dp</dimen>
-</resources>
diff --git a/packages/Osu/res/values/strings.xml b/packages/Osu/res/values/strings.xml
deleted file mode 100644
index 93593dc0be50..000000000000
--- a/packages/Osu/res/values/strings.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<resources>
- <string name="app_name">OSU</string>
- <string name="no_osu">No OSU available</string>
-</resources>
diff --git a/packages/Osu/src/com/android/anqp/ANQPElement.java b/packages/Osu/src/com/android/anqp/ANQPElement.java
deleted file mode 100644
index 58aee29e106b..000000000000
--- a/packages/Osu/src/com/android/anqp/ANQPElement.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.android.anqp;
-
-/**
- * Base class for an IEEE802.11u ANQP element.
- */
-public abstract class ANQPElement {
- private final Constants.ANQPElementType mID;
-
- protected ANQPElement(Constants.ANQPElementType id) {
- mID = id;
- }
-
- public Constants.ANQPElementType getID() {
- return mID;
- }
-}
diff --git a/packages/Osu/src/com/android/anqp/Constants.java b/packages/Osu/src/com/android/anqp/Constants.java
deleted file mode 100644
index 214bb93f41dd..000000000000
--- a/packages/Osu/src/com/android/anqp/Constants.java
+++ /dev/null
@@ -1,233 +0,0 @@
-package com.android.anqp;
-
-import java.net.ProtocolException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.charset.Charset;
-import java.util.Collection;
-import java.util.EnumMap;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * ANQP related constants (802.11-2012)
- */
-public class Constants {
-
- public static final int NIBBLE_MASK = 0x0f;
- public static final int BYTE_MASK = 0xff;
- public static final int SHORT_MASK = 0xffff;
- public static final long INT_MASK = 0xffffffffL;
- public static final int BYTES_IN_SHORT = 2;
- public static final int BYTES_IN_INT = 4;
- public static final int BYTES_IN_EUI48 = 6;
- public static final long MILLIS_IN_A_SEC = 1000L;
-
- public static final int HS20_PREFIX = 0x119a6f50; // Note that this is represented as a LE int
- public static final int HS20_FRAME_PREFIX = 0x109a6f50;
- public static final int UTF8_INDICATOR = 1;
-
- public static final int LANG_CODE_LENGTH = 3;
-
- public static final int ANQP_QUERY_LIST = 256;
- public static final int ANQP_CAPABILITY_LIST = 257;
- public static final int ANQP_VENUE_NAME = 258;
- public static final int ANQP_EMERGENCY_NUMBER = 259;
- public static final int ANQP_NWK_AUTH_TYPE = 260;
- public static final int ANQP_ROAMING_CONSORTIUM = 261;
- public static final int ANQP_IP_ADDR_AVAILABILITY = 262;
- public static final int ANQP_NAI_REALM = 263;
- public static final int ANQP_3GPP_NETWORK = 264;
- public static final int ANQP_GEO_LOC = 265;
- public static final int ANQP_CIVIC_LOC = 266;
- public static final int ANQP_LOC_URI = 267;
- public static final int ANQP_DOM_NAME = 268;
- public static final int ANQP_EMERGENCY_ALERT = 269;
- public static final int ANQP_TDLS_CAP = 270;
- public static final int ANQP_EMERGENCY_NAI = 271;
- public static final int ANQP_NEIGHBOR_REPORT = 272;
- public static final int ANQP_VENDOR_SPEC = 56797;
-
- public static final int HS_QUERY_LIST = 1;
- public static final int HS_CAPABILITY_LIST = 2;
- public static final int HS_FRIENDLY_NAME = 3;
- public static final int HS_WAN_METRICS = 4;
- public static final int HS_CONN_CAPABILITY = 5;
- public static final int HS_NAI_HOME_REALM_QUERY = 6;
- public static final int HS_OPERATING_CLASS = 7;
- public static final int HS_OSU_PROVIDERS = 8;
- public static final int HS_ICON_REQUEST = 10;
- public static final int HS_ICON_FILE = 11;
-
- public enum ANQPElementType {
- ANQPQueryList,
- ANQPCapabilityList,
- ANQPVenueName,
- ANQPEmergencyNumber,
- ANQPNwkAuthType,
- ANQPRoamingConsortium,
- ANQPIPAddrAvailability,
- ANQPNAIRealm,
- ANQP3GPPNetwork,
- ANQPGeoLoc,
- ANQPCivicLoc,
- ANQPLocURI,
- ANQPDomName,
- ANQPEmergencyAlert,
- ANQPTDLSCap,
- ANQPEmergencyNAI,
- ANQPNeighborReport,
- ANQPVendorSpec,
- HSQueryList,
- HSCapabilityList,
- HSFriendlyName,
- HSWANMetrics,
- HSConnCapability,
- HSNAIHomeRealmQuery,
- HSOperatingclass,
- HSOSUProviders,
- HSIconRequest,
- HSIconFile
- }
-
- private static final Map<Integer, ANQPElementType> sAnqpMap = new HashMap<>();
- private static final Map<Integer, ANQPElementType> sHs20Map = new HashMap<>();
- private static final Map<ANQPElementType, Integer> sRevAnqpmap =
- new EnumMap<>(ANQPElementType.class);
- private static final Map<ANQPElementType, Integer> sRevHs20map =
- new EnumMap<>(ANQPElementType.class);
-
- static {
- sAnqpMap.put(ANQP_QUERY_LIST, ANQPElementType.ANQPQueryList);
- sAnqpMap.put(ANQP_CAPABILITY_LIST, ANQPElementType.ANQPCapabilityList);
- sAnqpMap.put(ANQP_VENUE_NAME, ANQPElementType.ANQPVenueName);
- sAnqpMap.put(ANQP_EMERGENCY_NUMBER, ANQPElementType.ANQPEmergencyNumber);
- sAnqpMap.put(ANQP_NWK_AUTH_TYPE, ANQPElementType.ANQPNwkAuthType);
- sAnqpMap.put(ANQP_ROAMING_CONSORTIUM, ANQPElementType.ANQPRoamingConsortium);
- sAnqpMap.put(ANQP_IP_ADDR_AVAILABILITY, ANQPElementType.ANQPIPAddrAvailability);
- sAnqpMap.put(ANQP_NAI_REALM, ANQPElementType.ANQPNAIRealm);
- sAnqpMap.put(ANQP_3GPP_NETWORK, ANQPElementType.ANQP3GPPNetwork);
- sAnqpMap.put(ANQP_GEO_LOC, ANQPElementType.ANQPGeoLoc);
- sAnqpMap.put(ANQP_CIVIC_LOC, ANQPElementType.ANQPCivicLoc);
- sAnqpMap.put(ANQP_LOC_URI, ANQPElementType.ANQPLocURI);
- sAnqpMap.put(ANQP_DOM_NAME, ANQPElementType.ANQPDomName);
- sAnqpMap.put(ANQP_EMERGENCY_ALERT, ANQPElementType.ANQPEmergencyAlert);
- sAnqpMap.put(ANQP_TDLS_CAP, ANQPElementType.ANQPTDLSCap);
- sAnqpMap.put(ANQP_EMERGENCY_NAI, ANQPElementType.ANQPEmergencyNAI);
- sAnqpMap.put(ANQP_NEIGHBOR_REPORT, ANQPElementType.ANQPNeighborReport);
- sAnqpMap.put(ANQP_VENDOR_SPEC, ANQPElementType.ANQPVendorSpec);
-
- sHs20Map.put(HS_QUERY_LIST, ANQPElementType.HSQueryList);
- sHs20Map.put(HS_CAPABILITY_LIST, ANQPElementType.HSCapabilityList);
- sHs20Map.put(HS_FRIENDLY_NAME, ANQPElementType.HSFriendlyName);
- sHs20Map.put(HS_WAN_METRICS, ANQPElementType.HSWANMetrics);
- sHs20Map.put(HS_CONN_CAPABILITY, ANQPElementType.HSConnCapability);
- sHs20Map.put(HS_NAI_HOME_REALM_QUERY, ANQPElementType.HSNAIHomeRealmQuery);
- sHs20Map.put(HS_OPERATING_CLASS, ANQPElementType.HSOperatingclass);
- sHs20Map.put(HS_OSU_PROVIDERS, ANQPElementType.HSOSUProviders);
- sHs20Map.put(HS_ICON_REQUEST, ANQPElementType.HSIconRequest);
- sHs20Map.put(HS_ICON_FILE, ANQPElementType.HSIconFile);
-
- for (Map.Entry<Integer, ANQPElementType> entry : sAnqpMap.entrySet()) {
- sRevAnqpmap.put(entry.getValue(), entry.getKey());
- }
- for (Map.Entry<Integer, ANQPElementType> entry : sHs20Map.entrySet()) {
- sRevHs20map.put(entry.getValue(), entry.getKey());
- }
- }
-
- public static ANQPElementType mapANQPElement(int id) {
- return sAnqpMap.get(id);
- }
-
- public static ANQPElementType mapHS20Element(int id) {
- return sHs20Map.get(id);
- }
-
- public static Integer getANQPElementID(ANQPElementType elementType) {
- return sRevAnqpmap.get(elementType);
- }
-
- public static Integer getHS20ElementID(ANQPElementType elementType) {
- return sRevHs20map.get(elementType);
- }
-
- public static boolean hasBaseANQPElements(Collection<ANQPElementType> elements) {
- if (elements == null) {
- return false;
- }
- for (ANQPElementType element : elements) {
- if (sRevAnqpmap.containsKey(element)) {
- return true;
- }
- }
- return false;
- }
-
- public static boolean hasR2Elements(List<ANQPElementType> elements) {
- return elements.contains(ANQPElementType.HSOSUProviders);
- }
-
- public static long getInteger(ByteBuffer payload, ByteOrder bo, int size) {
- byte[] octets = new byte[size];
- payload.get(octets);
- long value = 0;
- if (bo == ByteOrder.LITTLE_ENDIAN) {
- for (int n = octets.length - 1; n >= 0; n--) {
- value = (value << Byte.SIZE) | (octets[n] & BYTE_MASK);
- }
- }
- else {
- for (byte octet : octets) {
- value = (value << Byte.SIZE) | (octet & BYTE_MASK);
- }
- }
- return value;
- }
-
- public static String getPrefixedString(ByteBuffer payload, int lengthLength, Charset charset)
- throws ProtocolException {
- return getPrefixedString(payload, lengthLength, charset, false);
- }
-
- public static String getPrefixedString(ByteBuffer payload, int lengthLength, Charset charset,
- boolean useNull) throws ProtocolException {
- if (payload.remaining() < lengthLength) {
- throw new ProtocolException("Runt string: " + payload.remaining());
- }
- return getString(payload, (int) getInteger(payload, ByteOrder.LITTLE_ENDIAN,
- lengthLength), charset, useNull);
- }
-
- public static String getTrimmedString(ByteBuffer payload, int length, Charset charset)
- throws ProtocolException {
- String s = getString(payload, length, charset, false);
- int zero = length - 1;
- while (zero >= 0) {
- if (s.charAt(zero) != 0) {
- break;
- }
- zero--;
- }
- return zero < length - 1 ? s.substring(0, zero + 1) : s;
- }
-
- public static String getString(ByteBuffer payload, int length, Charset charset)
- throws ProtocolException {
- return getString(payload, length, charset, false);
- }
-
- public static String getString(ByteBuffer payload, int length, Charset charset, boolean useNull)
- throws ProtocolException {
- if (length > payload.remaining()) {
- throw new ProtocolException("Bad string length: " + length);
- }
- if (useNull && length == 0) {
- return null;
- }
- byte[] octets = new byte[length];
- payload.get(octets);
- return new String(octets, charset);
- }
-}
diff --git a/packages/Osu/src/com/android/anqp/HSIconFileElement.java b/packages/Osu/src/com/android/anqp/HSIconFileElement.java
deleted file mode 100644
index 28c597a5d47a..000000000000
--- a/packages/Osu/src/com/android/anqp/HSIconFileElement.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package com.android.anqp;
-
-import android.os.Parcel;
-
-import com.android.hotspot2.Utils;
-
-import java.net.ProtocolException;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-
-import static com.android.anqp.Constants.BYTE_MASK;
-import static com.android.anqp.Constants.SHORT_MASK;
-
-/**
- * The Icon Binary File vendor specific ANQP Element,
- * Wi-Fi Alliance Hotspot 2.0 (Release 2) Technical Specification - Version 5.00,
- * section 4.11
- */
-public class HSIconFileElement extends ANQPElement {
-
- public enum StatusCode {Success, FileNotFound, Unspecified}
-
- private final StatusCode mStatusCode;
- private final String mType;
- private final byte[] mIconData;
-
- public HSIconFileElement(Constants.ANQPElementType infoID, ByteBuffer payload)
- throws ProtocolException {
- super(infoID);
-
- if (payload.remaining() < 4) {
- throw new ProtocolException("Truncated icon file: " + payload.remaining());
- }
-
- int statusID = payload.get() & BYTE_MASK;
- mStatusCode = statusID < StatusCode.values().length ? StatusCode.values()[statusID] : null;
- mType = Constants.getPrefixedString(payload, 1, StandardCharsets.US_ASCII);
-
- int dataLength = payload.getShort() & SHORT_MASK;
- mIconData = new byte[dataLength];
- payload.get(mIconData);
- }
-
- public StatusCode getStatusCode() {
- return mStatusCode;
- }
-
- public String getType() {
- return mType;
- }
-
- public byte[] getIconData() {
- return mIconData;
- }
-
- @Override
- public boolean equals(Object thatObject) {
- if (thatObject == this) {
- return true;
- } else if (thatObject.getClass() != HSIconFileElement.class) {
- return false;
- }
- HSIconFileElement that = (HSIconFileElement) thatObject;
- if (getStatusCode() != that.getStatusCode() || getStatusCode() != StatusCode.Success) {
- return false;
- }
- return getType().equals(that.getType()) && Arrays.equals(getIconData(), that.getIconData());
- }
-
- @Override
- public String toString() {
- return "HSIconFile{" +
- "statusCode=" + mStatusCode +
- ", type='" + mType + '\'' +
- ", iconData=" + mIconData.length + " bytes }";
- }
-
- public HSIconFileElement(Parcel in) {
- super(Constants.ANQPElementType.HSIconFile);
- mStatusCode = Utils.mapEnum(in.readInt(), StatusCode.class);
- mType = in.readString();
- mIconData = in.readBlob();
- }
-
- public void writeParcel(Parcel out) {
- out.writeInt(mStatusCode.ordinal());
- out.writeString(mType);
- out.writeBlob(mIconData);
- }
-}
diff --git a/packages/Osu/src/com/android/anqp/HSOsuProvidersElement.java b/packages/Osu/src/com/android/anqp/HSOsuProvidersElement.java
deleted file mode 100644
index 646e003ef350..000000000000
--- a/packages/Osu/src/com/android/anqp/HSOsuProvidersElement.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.android.anqp;
-
-import java.net.ProtocolException;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * The OSU Providers List vendor specific ANQP Element,
- * Wi-Fi Alliance Hotspot 2.0 (Release 2) Technical Specification - Version 5.00,
- * section 4.8
- */
-public class HSOsuProvidersElement extends ANQPElement {
- private final String mSSID;
- private final List<OSUProvider> mProviders;
-
- public HSOsuProvidersElement(Constants.ANQPElementType infoID, ByteBuffer payload)
- throws ProtocolException {
- super(infoID);
-
- mSSID = Constants.getPrefixedString(payload, 1, StandardCharsets.UTF_8);
- int providerCount = payload.get() & Constants.BYTE_MASK;
-
- mProviders = new ArrayList<>(providerCount);
-
- while (providerCount > 0) {
- mProviders.add(new OSUProvider(mSSID, payload));
- providerCount--;
- }
- }
-
- public String getSSID() {
- return mSSID;
- }
-
- public List<OSUProvider> getProviders() {
- return Collections.unmodifiableList(mProviders);
- }
-
- @Override
- public String toString() {
- return "HSOsuProviders{" +
- "SSID='" + mSSID + '\'' +
- ", providers=" + mProviders +
- '}';
- }
-}
diff --git a/packages/Osu/src/com/android/anqp/I18Name.java b/packages/Osu/src/com/android/anqp/I18Name.java
deleted file mode 100644
index b048228722c5..000000000000
--- a/packages/Osu/src/com/android/anqp/I18Name.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.android.anqp;
-
-import android.os.Parcel;
-
-import java.io.IOException;
-import java.net.ProtocolException;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.Locale;
-
-import static com.android.anqp.Constants.BYTE_MASK;
-
-/**
- * A generic Internationalized name used in ANQP elements as specified in 802.11-2012 and
- * "Wi-Fi Alliance Hotspot 2.0 (Release 2) Technical Specification - Version 5.00"
- */
-public class I18Name {
- private final String mLanguage;
- private final Locale mLocale;
- private final String mText;
-
- public I18Name(ByteBuffer payload) throws ProtocolException {
- if (payload.remaining() < Constants.LANG_CODE_LENGTH + 1) {
- throw new ProtocolException("Truncated I18Name: " + payload.remaining());
- }
- int nameLength = payload.get() & BYTE_MASK;
- if (nameLength < Constants.LANG_CODE_LENGTH) {
- throw new ProtocolException("Runt I18Name: " + nameLength);
- }
- mLanguage = Constants.getTrimmedString(payload,
- Constants.LANG_CODE_LENGTH, StandardCharsets.US_ASCII);
- mLocale = Locale.forLanguageTag(mLanguage);
- mText = Constants.getString(payload, nameLength -
- Constants.LANG_CODE_LENGTH, StandardCharsets.UTF_8);
- }
-
- public I18Name(String compoundString) throws IOException {
- if (compoundString.length() < Constants.LANG_CODE_LENGTH) {
- throw new IOException("I18String too short: '" + compoundString + "'");
- }
- mLanguage = compoundString.substring(0, Constants.LANG_CODE_LENGTH);
- mText = compoundString.substring(Constants.LANG_CODE_LENGTH);
- mLocale = Locale.forLanguageTag(mLanguage);
- }
-
- public String getLanguage() {
- return mLanguage;
- }
-
- public Locale getLocale() {
- return mLocale;
- }
-
- public String getText() {
- return mText;
- }
-
- @Override
- public boolean equals(Object thatObject) {
- if (this == thatObject) {
- return true;
- }
- if (thatObject == null || getClass() != thatObject.getClass()) {
- return false;
- }
-
- I18Name that = (I18Name) thatObject;
- return mLanguage.equals(that.mLanguage) && mText.equals(that.mText);
- }
-
- @Override
- public int hashCode() {
- int result = mLanguage.hashCode();
- result = 31 * result + mText.hashCode();
- return result;
- }
-
- @Override
- public String toString() {
- return mText + ':' + mLocale.getLanguage();
- }
-
- public I18Name(Parcel in) throws IOException {
- mLanguage = in.readString();
- mText = in.readString();
- mLocale = Locale.forLanguageTag(mLanguage);
- }
-
- public void writeParcel(Parcel out) {
- out.writeString(mLanguage);
- out.writeString(mText);
- }
-}
diff --git a/packages/Osu/src/com/android/anqp/IconInfo.java b/packages/Osu/src/com/android/anqp/IconInfo.java
deleted file mode 100644
index ac507c7af948..000000000000
--- a/packages/Osu/src/com/android/anqp/IconInfo.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package com.android.anqp;
-
-import android.os.Parcel;
-
-import java.net.ProtocolException;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-
-import static com.android.anqp.Constants.SHORT_MASK;
-
-/**
- * The Icons available OSU Providers sub field, as specified in
- * Wi-Fi Alliance Hotspot 2.0 (Release 2) Technical Specification - Version 5.00,
- * section 4.8.1.4
- */
-public class IconInfo {
- private final int mWidth;
- private final int mHeight;
- private final String mLanguage;
- private final String mIconType;
- private final String mFileName;
-
- public IconInfo(ByteBuffer payload) throws ProtocolException {
- if (payload.remaining() < 9) {
- throw new ProtocolException("Truncated icon meta data");
- }
-
- mWidth = payload.getShort() & SHORT_MASK;
- mHeight = payload.getShort() & SHORT_MASK;
- mLanguage = Constants.getTrimmedString(payload,
- Constants.LANG_CODE_LENGTH, StandardCharsets.US_ASCII);
- mIconType = Constants.getPrefixedString(payload, 1, StandardCharsets.US_ASCII);
- mFileName = Constants.getPrefixedString(payload, 1, StandardCharsets.UTF_8);
- }
-
- public int getWidth() {
- return mWidth;
- }
-
- public int getHeight() {
- return mHeight;
- }
-
- public String getLanguage() {
- return mLanguage;
- }
-
- public String getIconType() {
- return mIconType;
- }
-
- public String getFileName() {
- return mFileName;
- }
-
- @Override
- public boolean equals(Object thatObject) {
- if (this == thatObject) {
- return true;
- }
- if (thatObject == null || getClass() != thatObject.getClass()) {
- return false;
- }
-
- IconInfo that = (IconInfo) thatObject;
- return mHeight == that.mHeight &&
- mWidth == that.mWidth &&
- mFileName.equals(that.mFileName) &&
- mIconType.equals(that.mIconType) &&
- mLanguage.equals(that.mLanguage);
- }
-
- @Override
- public int hashCode() {
- int result = mWidth;
- result = 31 * result + mHeight;
- result = 31 * result + mLanguage.hashCode();
- result = 31 * result + mIconType.hashCode();
- result = 31 * result + mFileName.hashCode();
- return result;
- }
-
- @Override
- public String toString() {
- return "IconInfo{" +
- "Width=" + mWidth +
- ", Height=" + mHeight +
- ", Language=" + mLanguage +
- ", IconType='" + mIconType + '\'' +
- ", FileName='" + mFileName + '\'' +
- '}';
- }
-
- public IconInfo(Parcel in) {
- mWidth = in.readInt();
- mHeight = in.readInt();
- mLanguage = in.readString();
- mIconType = in.readString();
- mFileName = in.readString();
- }
-
- public void writeParcel(Parcel out) {
- out.writeInt(mWidth);
- out.writeInt(mHeight);
- out.writeString(mLanguage);
- out.writeString(mIconType);
- out.writeString(mFileName);
- }
-}
diff --git a/packages/Osu/src/com/android/anqp/OSUProvider.java b/packages/Osu/src/com/android/anqp/OSUProvider.java
deleted file mode 100644
index 3724cf06d15b..000000000000
--- a/packages/Osu/src/com/android/anqp/OSUProvider.java
+++ /dev/null
@@ -1,213 +0,0 @@
-package com.android.anqp;
-
-import android.os.Parcel;
-
-import com.android.hotspot2.Utils;
-
-import java.io.IOException;
-import java.net.ProtocolException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-
-import static com.android.anqp.Constants.BYTE_MASK;
-import static com.android.anqp.Constants.SHORT_MASK;
-
-/**
- * An OSU Provider, as specified in
- * Wi-Fi Alliance Hotspot 2.0 (Release 2) Technical Specification - Version 5.00,
- * section 4.8.1
- */
-public class OSUProvider {
-
- public enum OSUMethod {OmaDm, SoapXml}
-
- private final String mSSID;
- private final List<I18Name> mNames;
- private final String mOSUServer;
- private final List<OSUMethod> mOSUMethods;
- private final List<IconInfo> mIcons;
- private final String mOsuNai;
- private final List<I18Name> mServiceDescriptions;
- private final int mHashCode;
-
- public OSUProvider(String ssid, ByteBuffer payload) throws ProtocolException {
- if (payload.remaining() < 11) {
- throw new ProtocolException("Truncated OSU provider: " + payload.remaining());
- }
-
- mSSID = ssid;
-
- int length = payload.getShort() & SHORT_MASK;
- int namesLength = payload.getShort() & SHORT_MASK;
-
- ByteBuffer namesBuffer = payload.duplicate().order(ByteOrder.LITTLE_ENDIAN);
- namesBuffer.limit(namesBuffer.position() + namesLength);
- payload.position(payload.position() + namesLength);
-
- mNames = new ArrayList<>();
-
- while (namesBuffer.hasRemaining()) {
- mNames.add(new I18Name(namesBuffer));
- }
-
- mOSUServer = Constants.getPrefixedString(payload, 1, StandardCharsets.UTF_8);
- int methodLength = payload.get() & BYTE_MASK;
- mOSUMethods = new ArrayList<>(methodLength);
- while (methodLength > 0) {
- int methodID = payload.get() & BYTE_MASK;
- mOSUMethods.add(methodID < OSUMethod.values().length ?
- OSUMethod.values()[methodID] :
- null);
- methodLength--;
- }
-
- int iconsLength = payload.getShort() & SHORT_MASK;
- ByteBuffer iconsBuffer = payload.duplicate().order(ByteOrder.LITTLE_ENDIAN);
- iconsBuffer.limit(iconsBuffer.position() + iconsLength);
- payload.position(payload.position() + iconsLength);
-
- mIcons = new ArrayList<>();
-
- while (iconsBuffer.hasRemaining()) {
- mIcons.add(new IconInfo(iconsBuffer));
- }
-
- mOsuNai = Constants.getPrefixedString(payload, 1, StandardCharsets.UTF_8, true);
-
- int descriptionsLength = payload.getShort() & SHORT_MASK;
- ByteBuffer descriptionsBuffer = payload.duplicate().order(ByteOrder.LITTLE_ENDIAN);
- descriptionsBuffer.limit(descriptionsBuffer.position() + descriptionsLength);
- payload.position(payload.position() + descriptionsLength);
-
- mServiceDescriptions = new ArrayList<>();
-
- while (descriptionsBuffer.hasRemaining()) {
- mServiceDescriptions.add(new I18Name(descriptionsBuffer));
- }
-
- int result = mNames.hashCode();
- result = 31 * result + mSSID.hashCode();
- result = 31 * result + mOSUServer.hashCode();
- result = 31 * result + mOSUMethods.hashCode();
- result = 31 * result + mIcons.hashCode();
- result = 31 * result + (mOsuNai != null ? mOsuNai.hashCode() : 0);
- result = 31 * result + mServiceDescriptions.hashCode();
- mHashCode = result;
- }
-
- public String getSSID() {
- return mSSID;
- }
-
- public List<I18Name> getNames() {
- return mNames;
- }
-
- public String getOSUServer() {
- return mOSUServer;
- }
-
- public List<OSUMethod> getOSUMethods() {
- return mOSUMethods;
- }
-
- public List<IconInfo> getIcons() {
- return mIcons;
- }
-
- public String getOsuNai() {
- return mOsuNai;
- }
-
- public List<I18Name> getServiceDescriptions() {
- return mServiceDescriptions;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- OSUProvider that = (OSUProvider) o;
-
- if (!mSSID.equals(that.mSSID)) return false;
- if (!mOSUServer.equals(that.mOSUServer)) return false;
- if (!mNames.equals(that.mNames)) return false;
- if (!mServiceDescriptions.equals(that.mServiceDescriptions)) return false;
- if (!mIcons.equals(that.mIcons)) return false;
- if (!mOSUMethods.equals(that.mOSUMethods)) return false;
- if (mOsuNai != null ? !mOsuNai.equals(that.mOsuNai) : that.mOsuNai != null) return false;
-
- return true;
- }
-
- @Override
- public int hashCode() {
- return mHashCode;
- }
-
- @Override
- public String toString() {
- return "OSUProvider{" +
- "names=" + mNames +
- ", OSUServer='" + mOSUServer + '\'' +
- ", OSUMethods=" + mOSUMethods +
- ", icons=" + mIcons +
- ", NAI='" + mOsuNai + '\'' +
- ", serviceDescriptions=" + mServiceDescriptions +
- '}';
- }
-
- public OSUProvider(Parcel in) throws IOException {
- mSSID = in.readString();
- int nameCount = in.readInt();
- mNames = new ArrayList<>(nameCount);
- for (int n = 0; n < nameCount; n++) {
- mNames.add(new I18Name(in));
- }
- mOSUServer = in.readString();
- int methodCount = in.readInt();
- mOSUMethods = new ArrayList<>(methodCount);
- for (int n = 0; n < methodCount; n++) {
- mOSUMethods.add(Utils.mapEnum(in.readInt(), OSUMethod.class));
- }
- int iconCount = in.readInt();
- mIcons = new ArrayList<>(iconCount);
- for (int n = 0; n < iconCount; n++) {
- mIcons.add(new IconInfo(in));
- }
- mOsuNai = in.readString();
- int serviceCount = in.readInt();
- mServiceDescriptions = new ArrayList<>(serviceCount);
- for (int n = 0; n < serviceCount; n++) {
- mServiceDescriptions.add(new I18Name(in));
- }
- mHashCode = in.readInt();
- }
-
- public void writeParcel(Parcel out) {
- out.writeString(mSSID);
- out.writeInt(mNames.size());
- for (I18Name name : mNames) {
- name.writeParcel(out);
- }
- out.writeString(mOSUServer);
- out.writeInt(mOSUMethods.size());
- for (OSUMethod method : mOSUMethods) {
- out.writeInt(method.ordinal());
- }
- out.writeInt(mIcons.size());
- for (IconInfo iconInfo : mIcons) {
- iconInfo.writeParcel(out);
- }
- out.writeString(mOsuNai);
- out.writeInt(mServiceDescriptions.size());
- for (I18Name serviceDescription : mServiceDescriptions) {
- serviceDescription.writeParcel(out);
- }
- out.writeInt(mHashCode);
- }
-}
diff --git a/packages/Osu/src/com/android/anqp/eap/AuthParam.java b/packages/Osu/src/com/android/anqp/eap/AuthParam.java
deleted file mode 100644
index 4243954a61bd..000000000000
--- a/packages/Osu/src/com/android/anqp/eap/AuthParam.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.android.anqp.eap;
-
-/**
- * An Authentication parameter, part of the NAI Realm ANQP element, specified in
- * IEEE802.11-2012 section 8.4.4.10, table 8-188
- */
-public interface AuthParam {
- public EAP.AuthInfoID getAuthInfoID();
-}
diff --git a/packages/Osu/src/com/android/anqp/eap/Credential.java b/packages/Osu/src/com/android/anqp/eap/Credential.java
deleted file mode 100644
index 0a89f4fffe9d..000000000000
--- a/packages/Osu/src/com/android/anqp/eap/Credential.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package com.android.anqp.eap;
-
-import java.net.ProtocolException;
-import java.nio.ByteBuffer;
-
-import static com.android.anqp.Constants.BYTE_MASK;
-
-/**
- * An EAP authentication parameter, IEEE802.11-2012, table 8-188
- */
-public class Credential implements AuthParam {
-
- public enum CredType {
- Reserved,
- SIM,
- USIM,
- NFC,
- HWToken,
- Softoken,
- Certificate,
- Username,
- None,
- Anonymous,
- VendorSpecific}
-
- private final EAP.AuthInfoID mAuthInfoID;
- private final CredType mCredType;
-
- public Credential(EAP.AuthInfoID infoID, int length, ByteBuffer payload)
- throws ProtocolException {
- if (length != 1) {
- throw new ProtocolException("Bad length: " + length);
- }
-
- mAuthInfoID = infoID;
- int typeID = payload.get() & BYTE_MASK;
-
- mCredType = typeID < CredType.values().length ?
- CredType.values()[typeID] :
- CredType.Reserved;
- }
-
- @Override
- public EAP.AuthInfoID getAuthInfoID() {
- return mAuthInfoID;
- }
-
- @Override
- public int hashCode() {
- return mAuthInfoID.hashCode() * 31 + mCredType.hashCode();
- }
-
- @Override
- public boolean equals(Object thatObject) {
- if (thatObject == this) {
- return true;
- } else if (thatObject == null || thatObject.getClass() != Credential.class) {
- return false;
- } else {
- return ((Credential) thatObject).getCredType() == getCredType();
- }
- }
-
- public CredType getCredType() {
- return mCredType;
- }
-
- @Override
- public String toString() {
- return "Auth method " + mAuthInfoID + " = " + mCredType + "\n";
- }
-}
diff --git a/packages/Osu/src/com/android/anqp/eap/EAP.java b/packages/Osu/src/com/android/anqp/eap/EAP.java
deleted file mode 100644
index 4b968b6cbf39..000000000000
--- a/packages/Osu/src/com/android/anqp/eap/EAP.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package com.android.anqp.eap;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-/**
- * EAP Related constants for the ANQP NAIRealm element, IEEE802.11-2012 section 8.4.4.10
- */
-public abstract class EAP {
-
- private static final Map<Integer, EAPMethodID> sEapIds = new HashMap<>();
- private static final Map<EAPMethodID, Integer> sRevEapIds = new HashMap<>();
- private static final Map<Integer, AuthInfoID> sAuthIds = new HashMap<>();
-
- public static final int EAP_MD5 = 4;
- public static final int EAP_OTP = 5;
- public static final int EAP_RSA = 9;
- public static final int EAP_KEA = 11;
- public static final int EAP_KEA_VALIDATE = 12;
- public static final int EAP_TLS = 13;
- public static final int EAP_LEAP = 17;
- public static final int EAP_SIM = 18;
- public static final int EAP_TTLS = 21;
- public static final int EAP_AKA = 23;
- public static final int EAP_3Com = 24;
- public static final int EAP_MSCHAPv2 = 26;
- public static final int EAP_PEAP = 29;
- public static final int EAP_POTP = 32;
- public static final int EAP_ActiontecWireless = 35;
- public static final int EAP_HTTPDigest = 38;
- public static final int EAP_SPEKE = 41;
- public static final int EAP_MOBAC = 42;
- public static final int EAP_FAST = 43;
- public static final int EAP_ZLXEAP = 44;
- public static final int EAP_Link = 45;
- public static final int EAP_PAX = 46;
- public static final int EAP_PSK = 47;
- public static final int EAP_SAKE = 48;
- public static final int EAP_IKEv2 = 49;
- public static final int EAP_AKAPrim = 50;
- public static final int EAP_GPSK = 51;
- public static final int EAP_PWD = 52;
- public static final int EAP_EKE = 53;
- public static final int EAP_TEAP = 55;
-
- public enum EAPMethodID {
- EAP_MD5,
- EAP_OTP,
- EAP_RSA,
- EAP_KEA,
- EAP_KEA_VALIDATE,
- EAP_TLS,
- EAP_LEAP,
- EAP_SIM,
- EAP_TTLS,
- EAP_AKA,
- EAP_3Com,
- EAP_MSCHAPv2,
- EAP_PEAP,
- EAP_POTP,
- EAP_ActiontecWireless,
- EAP_HTTPDigest,
- EAP_SPEKE,
- EAP_MOBAC,
- EAP_FAST,
- EAP_ZLXEAP,
- EAP_Link,
- EAP_PAX,
- EAP_PSK,
- EAP_SAKE,
- EAP_IKEv2,
- EAP_AKAPrim,
- EAP_GPSK,
- EAP_PWD,
- EAP_EKE,
- EAP_TEAP
- }
-
- public static final int ExpandedEAPMethod = 1;
- public static final int NonEAPInnerAuthType = 2;
- public static final int InnerAuthEAPMethodType = 3;
- public static final int ExpandedInnerEAPMethod = 4;
- public static final int CredentialType = 5;
- public static final int TunneledEAPMethodCredType = 6;
- public static final int VendorSpecific = 221;
-
- public enum AuthInfoID {
- Undefined,
- ExpandedEAPMethod,
- NonEAPInnerAuthType,
- InnerAuthEAPMethodType,
- ExpandedInnerEAPMethod,
- CredentialType,
- TunneledEAPMethodCredType,
- VendorSpecific
- }
-
- static {
- sEapIds.put(EAP_MD5, EAPMethodID.EAP_MD5);
- sEapIds.put(EAP_OTP, EAPMethodID.EAP_OTP);
- sEapIds.put(EAP_RSA, EAPMethodID.EAP_RSA);
- sEapIds.put(EAP_KEA, EAPMethodID.EAP_KEA);
- sEapIds.put(EAP_KEA_VALIDATE, EAPMethodID.EAP_KEA_VALIDATE);
- sEapIds.put(EAP_TLS, EAPMethodID.EAP_TLS);
- sEapIds.put(EAP_LEAP, EAPMethodID.EAP_LEAP);
- sEapIds.put(EAP_SIM, EAPMethodID.EAP_SIM);
- sEapIds.put(EAP_TTLS, EAPMethodID.EAP_TTLS);
- sEapIds.put(EAP_AKA, EAPMethodID.EAP_AKA);
- sEapIds.put(EAP_3Com, EAPMethodID.EAP_3Com);
- sEapIds.put(EAP_MSCHAPv2, EAPMethodID.EAP_MSCHAPv2);
- sEapIds.put(EAP_PEAP, EAPMethodID.EAP_PEAP);
- sEapIds.put(EAP_POTP, EAPMethodID.EAP_POTP);
- sEapIds.put(EAP_ActiontecWireless, EAPMethodID.EAP_ActiontecWireless);
- sEapIds.put(EAP_HTTPDigest, EAPMethodID.EAP_HTTPDigest);
- sEapIds.put(EAP_SPEKE, EAPMethodID.EAP_SPEKE);
- sEapIds.put(EAP_MOBAC, EAPMethodID.EAP_MOBAC);
- sEapIds.put(EAP_FAST, EAPMethodID.EAP_FAST);
- sEapIds.put(EAP_ZLXEAP, EAPMethodID.EAP_ZLXEAP);
- sEapIds.put(EAP_Link, EAPMethodID.EAP_Link);
- sEapIds.put(EAP_PAX, EAPMethodID.EAP_PAX);
- sEapIds.put(EAP_PSK, EAPMethodID.EAP_PSK);
- sEapIds.put(EAP_SAKE, EAPMethodID.EAP_SAKE);
- sEapIds.put(EAP_IKEv2, EAPMethodID.EAP_IKEv2);
- sEapIds.put(EAP_AKAPrim, EAPMethodID.EAP_AKAPrim);
- sEapIds.put(EAP_GPSK, EAPMethodID.EAP_GPSK);
- sEapIds.put(EAP_PWD, EAPMethodID.EAP_PWD);
- sEapIds.put(EAP_EKE, EAPMethodID.EAP_EKE);
- sEapIds.put(EAP_TEAP, EAPMethodID.EAP_TEAP);
-
- for (Map.Entry<Integer, EAPMethodID> entry : sEapIds.entrySet()) {
- sRevEapIds.put(entry.getValue(), entry.getKey());
- }
-
- sAuthIds.put(ExpandedEAPMethod, AuthInfoID.ExpandedEAPMethod);
- sAuthIds.put(NonEAPInnerAuthType, AuthInfoID.NonEAPInnerAuthType);
- sAuthIds.put(InnerAuthEAPMethodType, AuthInfoID.InnerAuthEAPMethodType);
- sAuthIds.put(ExpandedInnerEAPMethod, AuthInfoID.ExpandedInnerEAPMethod);
- sAuthIds.put(CredentialType, AuthInfoID.CredentialType);
- sAuthIds.put(TunneledEAPMethodCredType, AuthInfoID.TunneledEAPMethodCredType);
- sAuthIds.put(VendorSpecific, AuthInfoID.VendorSpecific);
- }
-
- public static EAPMethodID mapEAPMethod(int methodID) {
- return sEapIds.get(methodID);
- }
-
- public static Integer mapEAPMethod(EAPMethodID methodID) {
- return sRevEapIds.get(methodID);
- }
-
- public static AuthInfoID mapAuthMethod(int methodID) {
- return sAuthIds.get(methodID);
- }
-}
diff --git a/packages/Osu/src/com/android/anqp/eap/EAPMethod.java b/packages/Osu/src/com/android/anqp/eap/EAPMethod.java
deleted file mode 100644
index fa6c2f9dfb60..000000000000
--- a/packages/Osu/src/com/android/anqp/eap/EAPMethod.java
+++ /dev/null
@@ -1,191 +0,0 @@
-package com.android.anqp.eap;
-
-import com.android.anqp.Constants;
-import com.android.hotspot2.AuthMatch;
-
-import java.net.ProtocolException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Collections;
-import java.util.EnumMap;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * An EAP Method, part of the NAI Realm ANQP element, specified in
- * IEEE802.11-2012 section 8.4.4.10, figure 8-420
- */
-public class EAPMethod {
- private final EAP.EAPMethodID mEAPMethodID;
- private final Map<EAP.AuthInfoID, Set<AuthParam>> mAuthParams;
-
- public EAPMethod(ByteBuffer payload) throws ProtocolException {
- if (payload.remaining() < 3) {
- throw new ProtocolException("Runt EAP Method: " + payload.remaining());
- }
-
- int length = payload.get() & Constants.BYTE_MASK;
- int methodID = payload.get() & Constants.BYTE_MASK;
- int count = payload.get() & Constants.BYTE_MASK;
-
- mEAPMethodID = EAP.mapEAPMethod(methodID);
- mAuthParams = new EnumMap<>(EAP.AuthInfoID.class);
-
- int realCount = 0;
-
- ByteBuffer paramPayload = payload.duplicate().order(ByteOrder.LITTLE_ENDIAN);
- paramPayload.limit(paramPayload.position() + length - 2);
- payload.position(payload.position() + length - 2);
- while (paramPayload.hasRemaining()) {
- int id = paramPayload.get() & Constants.BYTE_MASK;
-
- EAP.AuthInfoID authInfoID = EAP.mapAuthMethod(id);
- if (authInfoID == null) {
- throw new ProtocolException("Unknown auth parameter ID: " + id);
- }
-
- int len = paramPayload.get() & Constants.BYTE_MASK;
- if (len == 0 || len > paramPayload.remaining()) {
- throw new ProtocolException("Bad auth method length: " + len);
- }
-
- switch (authInfoID) {
- case ExpandedEAPMethod:
- addAuthParam(new ExpandedEAPMethod(authInfoID, len, paramPayload));
- break;
- case NonEAPInnerAuthType:
- addAuthParam(new NonEAPInnerAuth(len, paramPayload));
- break;
- case InnerAuthEAPMethodType:
- addAuthParam(new InnerAuthEAP(len, paramPayload));
- break;
- case ExpandedInnerEAPMethod:
- addAuthParam(new ExpandedEAPMethod(authInfoID, len, paramPayload));
- break;
- case CredentialType:
- addAuthParam(new Credential(authInfoID, len, paramPayload));
- break;
- case TunneledEAPMethodCredType:
- addAuthParam(new Credential(authInfoID, len, paramPayload));
- break;
- case VendorSpecific:
- addAuthParam(new VendorSpecificAuth(len, paramPayload));
- break;
- }
-
- realCount++;
- }
- if (realCount != count)
- throw new ProtocolException("Invalid parameter count: " + realCount +
- ", expected " + count);
- }
-
- public EAPMethod(EAP.EAPMethodID eapMethodID, AuthParam authParam) {
- mEAPMethodID = eapMethodID;
- mAuthParams = new HashMap<>(1);
- if (authParam != null) {
- Set<AuthParam> authParams = new HashSet<>();
- authParams.add(authParam);
- mAuthParams.put(authParam.getAuthInfoID(), authParams);
- }
- }
-
- private void addAuthParam(AuthParam param) {
- Set<AuthParam> authParams = mAuthParams.get(param.getAuthInfoID());
- if (authParams == null) {
- authParams = new HashSet<>();
- mAuthParams.put(param.getAuthInfoID(), authParams);
- }
- authParams.add(param);
- }
-
- public Map<EAP.AuthInfoID, Set<AuthParam>> getAuthParams() {
- return Collections.unmodifiableMap(mAuthParams);
- }
-
- public EAP.EAPMethodID getEAPMethodID() {
- return mEAPMethodID;
- }
-
- public int match(com.android.hotspot2.pps.Credential credential) {
-
- EAPMethod credMethod = credential.getEAPMethod();
- if (mEAPMethodID != credMethod.getEAPMethodID()) {
- return AuthMatch.None;
- }
-
- switch (mEAPMethodID) {
- case EAP_TTLS:
- if (mAuthParams.isEmpty()) {
- return AuthMatch.Method;
- }
- int paramCount = 0;
- for (Map.Entry<EAP.AuthInfoID, Set<AuthParam>> entry :
- credMethod.getAuthParams().entrySet()) {
- Set<AuthParam> params = mAuthParams.get(entry.getKey());
- if (params == null) {
- continue;
- }
-
- if (!Collections.disjoint(params, entry.getValue())) {
- return AuthMatch.MethodParam;
- }
- paramCount += params.size();
- }
- return paramCount > 0 ? AuthMatch.None : AuthMatch.Method;
- case EAP_TLS:
- return AuthMatch.MethodParam;
- case EAP_SIM:
- case EAP_AKA:
- case EAP_AKAPrim:
- return AuthMatch.Method;
- default:
- return AuthMatch.Method;
- }
- }
-
- public AuthParam getAuthParam() {
- if (mAuthParams.isEmpty()) {
- return null;
- }
- Set<AuthParam> params = mAuthParams.values().iterator().next();
- if (params.isEmpty()) {
- return null;
- }
- return params.iterator().next();
- }
-
- @Override
- public boolean equals(Object thatObject) {
- if (this == thatObject) {
- return true;
- }
- else if (thatObject == null || getClass() != thatObject.getClass()) {
- return false;
- }
-
- EAPMethod that = (EAPMethod) thatObject;
- return mEAPMethodID == that.mEAPMethodID && mAuthParams.equals(that.mAuthParams);
- }
-
- @Override
- public int hashCode() {
- int result = mEAPMethodID.hashCode();
- result = 31 * result + mAuthParams.hashCode();
- return result;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("EAP Method ").append(mEAPMethodID).append('\n');
- for (Set<AuthParam> paramSet : mAuthParams.values()) {
- for (AuthParam param : paramSet) {
- sb.append(" ").append(param.toString());
- }
- }
- return sb.toString();
- }
-}
diff --git a/packages/Osu/src/com/android/anqp/eap/ExpandedEAPMethod.java b/packages/Osu/src/com/android/anqp/eap/ExpandedEAPMethod.java
deleted file mode 100644
index 1358c09e2cbe..000000000000
--- a/packages/Osu/src/com/android/anqp/eap/ExpandedEAPMethod.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package com.android.anqp.eap;
-
-import java.net.ProtocolException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-import static com.android.anqp.Constants.BYTE_MASK;
-import static com.android.anqp.Constants.INT_MASK;
-import static com.android.anqp.Constants.SHORT_MASK;
-
-/**
- * An EAP authentication parameter, IEEE802.11-2012, table 8-188
- */
-public class ExpandedEAPMethod implements AuthParam {
-
- private final EAP.AuthInfoID mAuthInfoID;
- private final int mVendorID;
- private final long mVendorType;
-
- public ExpandedEAPMethod(EAP.AuthInfoID authInfoID, int length, ByteBuffer payload)
- throws ProtocolException {
- if (length != 7) {
- throw new ProtocolException("Bad length: " + payload.remaining());
- }
-
- mAuthInfoID = authInfoID;
-
- ByteBuffer vndBuffer = payload.duplicate().order(ByteOrder.BIG_ENDIAN);
-
- int id = vndBuffer.getShort() & SHORT_MASK;
- id = (id << Byte.SIZE) | (vndBuffer.get() & BYTE_MASK);
- mVendorID = id;
- mVendorType = vndBuffer.getInt() & INT_MASK;
-
- payload.position(payload.position()+7);
- }
-
- public ExpandedEAPMethod(EAP.AuthInfoID authInfoID, int vendorID, long vendorType) {
- mAuthInfoID = authInfoID;
- mVendorID = vendorID;
- mVendorType = vendorType;
- }
-
- @Override
- public EAP.AuthInfoID getAuthInfoID() {
- return mAuthInfoID;
- }
-
- @Override
- public int hashCode() {
- return (mAuthInfoID.hashCode() * 31 + mVendorID) * 31 + (int) mVendorType;
- }
-
- @Override
- public boolean equals(Object thatObject) {
- if (thatObject == this) {
- return true;
- } else if (thatObject == null || thatObject.getClass() != ExpandedEAPMethod.class) {
- return false;
- } else {
- ExpandedEAPMethod that = (ExpandedEAPMethod) thatObject;
- return that.getVendorID() == getVendorID() && that.getVendorType() == getVendorType();
- }
- }
-
- public int getVendorID() {
- return mVendorID;
- }
-
- public long getVendorType() {
- return mVendorType;
- }
-
- @Override
- public String toString() {
- return "Auth method " + mAuthInfoID + ", id " + mVendorID + ", type " + mVendorType + "\n";
- }
-}
diff --git a/packages/Osu/src/com/android/anqp/eap/InnerAuthEAP.java b/packages/Osu/src/com/android/anqp/eap/InnerAuthEAP.java
deleted file mode 100644
index 571cf26fb72f..000000000000
--- a/packages/Osu/src/com/android/anqp/eap/InnerAuthEAP.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.android.anqp.eap;
-
-import java.net.ProtocolException;
-import java.nio.ByteBuffer;
-
-import static com.android.anqp.Constants.BYTE_MASK;
-
-/**
- * An EAP authentication parameter, IEEE802.11-2012, table 8-188
- */
-public class InnerAuthEAP implements AuthParam {
-
- private final EAP.EAPMethodID mEapMethodID;
-
- public InnerAuthEAP(int length, ByteBuffer payload) throws ProtocolException {
- if (length != 1) {
- throw new ProtocolException("Bad length: " + length);
- }
- int typeID = payload.get() & BYTE_MASK;
- mEapMethodID = EAP.mapEAPMethod(typeID);
- }
-
- public InnerAuthEAP(EAP.EAPMethodID eapMethodID) {
- mEapMethodID = eapMethodID;
- }
-
- @Override
- public EAP.AuthInfoID getAuthInfoID() {
- return EAP.AuthInfoID.InnerAuthEAPMethodType;
- }
-
- public EAP.EAPMethodID getEAPMethodID() {
- return mEapMethodID;
- }
-
- @Override
- public int hashCode() {
- return mEapMethodID != null ? mEapMethodID.hashCode() : 0;
- }
-
- @Override
- public boolean equals(Object thatObject) {
- if (thatObject == this) {
- return true;
- } else if (thatObject == null || thatObject.getClass() != InnerAuthEAP.class) {
- return false;
- } else {
- return ((InnerAuthEAP) thatObject).getEAPMethodID() == getEAPMethodID();
- }
- }
-
- @Override
- public String toString() {
- return "Auth method InnerAuthEAP, inner = " + mEapMethodID + '\n';
- }
-}
diff --git a/packages/Osu/src/com/android/anqp/eap/NonEAPInnerAuth.java b/packages/Osu/src/com/android/anqp/eap/NonEAPInnerAuth.java
deleted file mode 100644
index 9d37b4dc15e4..000000000000
--- a/packages/Osu/src/com/android/anqp/eap/NonEAPInnerAuth.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.android.anqp.eap;
-
-import java.net.ProtocolException;
-import java.nio.ByteBuffer;
-import java.util.EnumMap;
-import java.util.HashMap;
-import java.util.Map;
-
-import static com.android.anqp.Constants.BYTE_MASK;
-
-/**
- * An EAP authentication parameter, IEEE802.11-2012, table 8-188
- */
-public class NonEAPInnerAuth implements AuthParam {
-
- public enum NonEAPType {Reserved, PAP, CHAP, MSCHAP, MSCHAPv2}
- private static final Map<NonEAPType, String> sOmaMap = new EnumMap<>(NonEAPType.class);
- private static final Map<String, NonEAPType> sRevOmaMap = new HashMap<>();
-
- private final NonEAPType mType;
-
- static {
- sOmaMap.put(NonEAPType.PAP, "PAP");
- sOmaMap.put(NonEAPType.CHAP, "CHAP");
- sOmaMap.put(NonEAPType.MSCHAP, "MS-CHAP");
- sOmaMap.put(NonEAPType.MSCHAPv2, "MS-CHAP-V2");
-
- for (Map.Entry<NonEAPType, String> entry : sOmaMap.entrySet()) {
- sRevOmaMap.put(entry.getValue(), entry.getKey());
- }
- }
-
- public NonEAPInnerAuth(int length, ByteBuffer payload) throws ProtocolException {
- if (length != 1) {
- throw new ProtocolException("Bad length: " + payload.remaining());
- }
-
- int typeID = payload.get() & BYTE_MASK;
- mType = typeID < NonEAPType.values().length ?
- NonEAPType.values()[typeID] :
- NonEAPType.Reserved;
- }
-
- public NonEAPInnerAuth(NonEAPType type) {
- mType = type;
- }
-
- /**
- * Construct from the OMA-DM PPS data
- * @param eapType as defined in the HS2.0 spec.
- */
- public NonEAPInnerAuth(String eapType) {
- mType = sRevOmaMap.get(eapType);
- }
-
- @Override
- public EAP.AuthInfoID getAuthInfoID() {
- return EAP.AuthInfoID.NonEAPInnerAuthType;
- }
-
- public NonEAPType getType() {
- return mType;
- }
-
- public String getOMAtype() {
- return sOmaMap.get(mType);
- }
-
- public static String mapInnerType(NonEAPType type) {
- return sOmaMap.get(type);
- }
-
- @Override
- public int hashCode() {
- return mType.hashCode();
- }
-
- @Override
- public boolean equals(Object thatObject) {
- if (thatObject == this) {
- return true;
- } else if (thatObject == null || thatObject.getClass() != NonEAPInnerAuth.class) {
- return false;
- } else {
- return ((NonEAPInnerAuth) thatObject).getType() == getType();
- }
- }
-
- @Override
- public String toString() {
- return "Auth method NonEAPInnerAuthEAP, inner = " + mType + '\n';
- }
-}
diff --git a/packages/Osu/src/com/android/anqp/eap/VendorSpecificAuth.java b/packages/Osu/src/com/android/anqp/eap/VendorSpecificAuth.java
deleted file mode 100644
index 04a315d37896..000000000000
--- a/packages/Osu/src/com/android/anqp/eap/VendorSpecificAuth.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.android.anqp.eap;
-
-import java.net.ProtocolException;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-
-/**
- * An EAP authentication parameter, IEEE802.11-2012, table 8-188
- */
-public class VendorSpecificAuth implements AuthParam {
-
- private final byte[] mData;
-
- public VendorSpecificAuth(int length, ByteBuffer payload) throws ProtocolException {
- mData = new byte[length];
- payload.get(mData);
- }
-
- @Override
- public EAP.AuthInfoID getAuthInfoID() {
- return EAP.AuthInfoID.VendorSpecific;
- }
-
- public int hashCode() {
- return Arrays.hashCode(mData);
- }
-
- @Override
- public boolean equals(Object thatObject) {
- if (thatObject == this) {
- return true;
- } else if (thatObject == null || thatObject.getClass() != VendorSpecificAuth.class) {
- return false;
- } else {
- return Arrays.equals(((VendorSpecificAuth) thatObject).getData(), getData());
- }
- }
-
- public byte[] getData() {
- return mData;
- }
-
- @Override
- public String toString() {
- return "Auth method VendorSpecificAuth, data = " + Arrays.toString(mData) + '\n';
- }
-}
diff --git a/packages/Osu/src/com/android/configparse/ConfigBuilder.java b/packages/Osu/src/com/android/configparse/ConfigBuilder.java
deleted file mode 100644
index b760ade764e3..000000000000
--- a/packages/Osu/src/com/android/configparse/ConfigBuilder.java
+++ /dev/null
@@ -1,258 +0,0 @@
-package com.android.configparse;
-
-import android.content.Context;
-import android.net.Uri;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiEnterpriseConfig;
-import android.util.Base64;
-import android.util.Log;
-
-import com.android.anqp.eap.AuthParam;
-import com.android.anqp.eap.EAP;
-import com.android.anqp.eap.EAPMethod;
-import com.android.anqp.eap.NonEAPInnerAuth;
-import com.android.hotspot2.IMSIParameter;
-import com.android.hotspot2.pps.Credential;
-import com.android.hotspot2.pps.HomeSP;
-
-import java.io.IOException;
-import java.security.GeneralSecurityException;
-import java.security.MessageDigest;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-
-public class ConfigBuilder {
- private static final String TAG = "WCFG";
-
- private static void dropFile(Uri uri, Context context) {
- context.getContentResolver().delete(uri, null, null);
- }
-
- public static WifiConfiguration buildConfig(HomeSP homeSP, X509Certificate caCert,
- List<X509Certificate> clientChain, PrivateKey key)
- throws IOException, GeneralSecurityException {
-
- Credential credential = homeSP.getCredential();
-
- WifiConfiguration config;
-
- EAP.EAPMethodID eapMethodID = credential.getEAPMethod().getEAPMethodID();
- switch (eapMethodID) {
- case EAP_TTLS:
- if (key != null || clientChain != null) {
- Log.w(TAG, "Client cert and/or key included with EAP-TTLS profile");
- }
- config = buildTTLSConfig(homeSP);
- break;
- case EAP_TLS:
- config = buildTLSConfig(homeSP, clientChain, key);
- break;
- case EAP_AKA:
- case EAP_AKAPrim:
- case EAP_SIM:
- if (key != null || clientChain != null || caCert != null) {
- Log.i(TAG, "Client/CA cert and/or key included with " +
- eapMethodID + " profile");
- }
- config = buildSIMConfig(homeSP);
- break;
- default:
- throw new IOException("Unsupported EAP Method: " + eapMethodID);
- }
-
- WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
-
- enterpriseConfig.setCaCertificate(caCert);
- enterpriseConfig.setAnonymousIdentity("anonymous@" + credential.getRealm());
-
- return config;
- }
-
- // Retain for debugging purposes
- /*
- private static void xIterateCerts(KeyStore ks, X509Certificate caCert)
- throws GeneralSecurityException {
- Enumeration<String> aliases = ks.aliases();
- while (aliases.hasMoreElements()) {
- String alias = aliases.nextElement();
- Certificate cert = ks.getCertificate(alias);
- Log.d("HS2J", "Checking " + alias);
- if (cert instanceof X509Certificate) {
- X509Certificate x509Certificate = (X509Certificate) cert;
- boolean sm = x509Certificate.getSubjectX500Principal().equals(
- caCert.getSubjectX500Principal());
- boolean eq = false;
- if (sm) {
- eq = Arrays.equals(x509Certificate.getEncoded(), caCert.getEncoded());
- }
- Log.d("HS2J", "Subject: " + x509Certificate.getSubjectX500Principal() +
- ": " + sm + "/" + eq);
- }
- }
- }
- */
-
- private static WifiConfiguration buildTTLSConfig(HomeSP homeSP)
- throws IOException {
- Credential credential = homeSP.getCredential();
-
- if (credential.getUserName() == null || credential.getPassword() == null) {
- throw new IOException("EAP-TTLS provisioned without user name or password");
- }
-
- EAPMethod eapMethod = credential.getEAPMethod();
-
- AuthParam authParam = eapMethod.getAuthParam();
- if (authParam == null ||
- authParam.getAuthInfoID() != EAP.AuthInfoID.NonEAPInnerAuthType) {
- throw new IOException("Bad auth parameter for EAP-TTLS: " + authParam);
- }
-
- WifiConfiguration config = buildBaseConfiguration(homeSP);
- NonEAPInnerAuth ttlsParam = (NonEAPInnerAuth) authParam;
- WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
- enterpriseConfig.setPhase2Method(remapInnerMethod(ttlsParam.getType()));
- enterpriseConfig.setIdentity(credential.getUserName());
- enterpriseConfig.setPassword(credential.getPassword());
-
- return config;
- }
-
- private static WifiConfiguration buildTLSConfig(HomeSP homeSP,
- List<X509Certificate> clientChain,
- PrivateKey clientKey)
- throws IOException, GeneralSecurityException {
-
- Credential credential = homeSP.getCredential();
-
- X509Certificate clientCertificate = null;
-
- if (clientKey == null || clientChain == null) {
- throw new IOException("No key and/or cert passed for EAP-TLS");
- }
- if (credential.getCertType() != Credential.CertType.x509v3) {
- throw new IOException("Invalid certificate type for TLS: " +
- credential.getCertType());
- }
-
- byte[] reference = credential.getFingerPrint();
- MessageDigest digester = MessageDigest.getInstance("SHA-256");
- for (X509Certificate certificate : clientChain) {
- digester.reset();
- byte[] fingerprint = digester.digest(certificate.getEncoded());
- if (Arrays.equals(reference, fingerprint)) {
- clientCertificate = certificate;
- break;
- }
- }
- if (clientCertificate == null) {
- throw new IOException("No certificate in chain matches supplied fingerprint");
- }
-
- String alias = Base64.encodeToString(reference, Base64.DEFAULT);
-
- WifiConfiguration config = buildBaseConfiguration(homeSP);
- WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
- enterpriseConfig.setClientCertificateAlias(alias);
- enterpriseConfig.setClientKeyEntry(clientKey, clientCertificate);
-
- return config;
- }
-
- private static WifiConfiguration buildSIMConfig(HomeSP homeSP)
- throws IOException {
-
- Credential credential = homeSP.getCredential();
- IMSIParameter credImsi = credential.getImsi();
-
- /*
- * Uncomment to enforce strict IMSI matching with currently installed SIM cards.
- *
- TelephonyManager tm = TelephonyManager.from(context);
- SubscriptionManager sub = SubscriptionManager.from(context);
- boolean match = false;
-
- for (int subId : sub.getActiveSubscriptionIdList()) {
- String imsi = tm.getSubscriberId(subId);
- if (credImsi.matches(imsi)) {
- match = true;
- break;
- }
- }
- if (!match) {
- throw new IOException("Supplied IMSI does not match any SIM card");
- }
- */
-
- WifiConfiguration config = buildBaseConfiguration(homeSP);
- config.enterpriseConfig.setPlmn(credImsi.toString());
- return config;
- }
-
- private static WifiConfiguration buildBaseConfiguration(HomeSP homeSP) throws IOException {
- EAP.EAPMethodID eapMethodID = homeSP.getCredential().getEAPMethod().getEAPMethodID();
-
- WifiConfiguration config = new WifiConfiguration();
-
- config.FQDN = homeSP.getFQDN();
-
- HashSet<Long> roamingConsortiumIds = homeSP.getRoamingConsortiums();
- config.roamingConsortiumIds = new long[roamingConsortiumIds.size()];
- int i = 0;
- for (long id : roamingConsortiumIds) {
- config.roamingConsortiumIds[i] = id;
- i++;
- }
- config.providerFriendlyName = homeSP.getFriendlyName();
-
- config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
- config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
-
- WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
- enterpriseConfig.setEapMethod(remapEAPMethod(eapMethodID));
- enterpriseConfig.setRealm(homeSP.getCredential().getRealm());
- if (homeSP.getUpdateIdentifier() >= 0) {
- config.updateIdentifier = Integer.toString(homeSP.getUpdateIdentifier());
- }
- config.enterpriseConfig = enterpriseConfig;
- if (homeSP.getUpdateIdentifier() >= 0) {
- config.updateIdentifier = Integer.toString(homeSP.getUpdateIdentifier());
- }
-
- return config;
- }
-
- private static int remapEAPMethod(EAP.EAPMethodID eapMethodID) throws IOException {
- switch (eapMethodID) {
- case EAP_TTLS:
- return WifiEnterpriseConfig.Eap.TTLS;
- case EAP_TLS:
- return WifiEnterpriseConfig.Eap.TLS;
- case EAP_SIM:
- return WifiEnterpriseConfig.Eap.SIM;
- case EAP_AKA:
- return WifiEnterpriseConfig.Eap.AKA;
- case EAP_AKAPrim:
- return WifiEnterpriseConfig.Eap.AKA_PRIME;
- default:
- throw new IOException("Bad EAP method: " + eapMethodID);
- }
- }
-
- private static int remapInnerMethod(NonEAPInnerAuth.NonEAPType type) throws IOException {
- switch (type) {
- case PAP:
- return WifiEnterpriseConfig.Phase2.PAP;
- case MSCHAP:
- return WifiEnterpriseConfig.Phase2.MSCHAP;
- case MSCHAPv2:
- return WifiEnterpriseConfig.Phase2.MSCHAPV2;
- case CHAP:
- default:
- throw new IOException("Inner method " + type + " not supported");
- }
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/AppBridge.java b/packages/Osu/src/com/android/hotspot2/AppBridge.java
deleted file mode 100644
index 81542f7fc466..000000000000
--- a/packages/Osu/src/com/android/hotspot2/AppBridge.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.android.hotspot2;
-
-import android.content.Context;
-import android.content.Intent;
-
-import com.android.hotspot2.osu.OSUOperationStatus;
-
-public class AppBridge {
- public static final String ACTION_OSU_NOTIFICATION = "com.android.hotspot2.OSU_NOTIFICATION";
- public static final String OSU_COUNT = "osu-count";
- public static final String SP_NAME = "sp-name";
- public static final String PROV_SUCCESS = "prov-success";
- public static final String DEAUTH = "deauth";
- public static final String DEAUTH_DELAY = "deauth-delay";
- public static final String DEAUTH_URL = "deauth-url";
- public static final String PROV_MESSAGE = "prov-message";
- public static final String OSU_INFO = "osu-info";
-
- public static final String GET_OSUS_ACTION = "com.android.hotspot2.GET_OSUS";
-
- private final Context mContext;
-
- public AppBridge(Context context) {
- mContext = context;
- }
-
- public void showOsuCount(int osuCount) {
- Intent intent = new Intent(ACTION_OSU_NOTIFICATION);
- intent.putExtra(OSU_COUNT, osuCount);
- intent.setFlags(
- Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
-
- mContext.startActivity(intent);
- }
-
- public void showStatus(OSUOperationStatus status, String spName, String message,
- String remoteStatus) {
- Intent intent = new Intent(ACTION_OSU_NOTIFICATION);
- intent.putExtra(SP_NAME, spName);
- intent.putExtra(PROV_SUCCESS, status == OSUOperationStatus.ProvisioningSuccess);
- if (message != null) {
- intent.putExtra(PROV_MESSAGE, message);
- }
- intent.setFlags(
- Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(intent);
- }
-
- public void showDeauth(String spName, boolean ess, int delay, String url) {
- Intent intent = new Intent(ACTION_OSU_NOTIFICATION);
- intent.putExtra(SP_NAME, spName);
- intent.putExtra(DEAUTH, ess);
- intent.putExtra(DEAUTH_DELAY, delay);
- intent.putExtra(DEAUTH_URL, url);
- intent.setFlags(
- Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(intent);
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/AuthMatch.java b/packages/Osu/src/com/android/hotspot2/AuthMatch.java
deleted file mode 100644
index f9c1f42955d1..000000000000
--- a/packages/Osu/src/com/android/hotspot2/AuthMatch.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.android.hotspot2;
-
-/**
- * Match score for EAP credentials:
- * None means that there is a distinct mismatch, i.e. realm, method or parameter is defined
- * and mismatches that of the credential.
- * Indeterminate means that there is no ANQP information to match against.
- * Note: The numeric values given to the constants are used for preference comparison and
- * must be maintained accordingly.
- */
-public abstract class AuthMatch {
- public static final int None = -1;
- public static final int Indeterminate = 0;
- public static final int Realm = 0x04;
- public static final int Method = 0x02;
- public static final int Param = 0x01;
- public static final int MethodParam = Method | Param;
- public static final int Exact = Realm | Method | Param;
-
- public static String toString(int match) {
- if (match < 0) {
- return "None";
- } else if (match == 0) {
- return "Indeterminate";
- }
-
- StringBuilder sb = new StringBuilder();
- if ((match & Realm) != 0) {
- sb.append("Realm");
- }
- if ((match & Method) != 0) {
- sb.append("Method");
- }
- if ((match & Param) != 0) {
- sb.append("Param");
- }
- return sb.toString();
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/IMSIParameter.java b/packages/Osu/src/com/android/hotspot2/IMSIParameter.java
deleted file mode 100644
index 1d5d95daadc1..000000000000
--- a/packages/Osu/src/com/android/hotspot2/IMSIParameter.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.android.hotspot2;
-
-import java.io.IOException;
-
-public class IMSIParameter {
- private final String mImsi;
- private final boolean mPrefix;
-
- public IMSIParameter(String imsi, boolean prefix) {
- mImsi = imsi;
- mPrefix = prefix;
- }
-
- public IMSIParameter(String imsi) throws IOException {
- if (imsi == null || imsi.length() == 0) {
- throw new IOException("Bad IMSI: '" + imsi + "'");
- }
-
- int nonDigit;
- char stopChar = '\0';
- for (nonDigit = 0; nonDigit < imsi.length(); nonDigit++) {
- stopChar = imsi.charAt(nonDigit);
- if (stopChar < '0' || stopChar > '9') {
- break;
- }
- }
-
- if (nonDigit == imsi.length()) {
- mImsi = imsi;
- mPrefix = false;
- } else if (nonDigit == imsi.length() - 1 && stopChar == '*') {
- mImsi = imsi.substring(0, nonDigit);
- mPrefix = true;
- } else {
- throw new IOException("Bad IMSI: '" + imsi + "'");
- }
- }
-
- public boolean matches(String fullIMSI) {
- if (mPrefix) {
- return mImsi.regionMatches(false, 0, fullIMSI, 0, mImsi.length());
- } else {
- return mImsi.equals(fullIMSI);
- }
- }
-
- public boolean matchesMccMnc(String mccMnc) {
- if (mPrefix) {
- // For a prefix match, the entire prefix must match the mcc+mnc
- return mImsi.regionMatches(false, 0, mccMnc, 0, mImsi.length());
- } else {
- // For regular match, the entire length of mcc+mnc must match this IMSI
- return mImsi.regionMatches(false, 0, mccMnc, 0, mccMnc.length());
- }
- }
-
- public boolean isPrefix() {
- return mPrefix;
- }
-
- public String getImsi() {
- return mImsi;
- }
-
- public int prefixLength() {
- return mImsi.length();
- }
-
- @Override
- public boolean equals(Object thatObject) {
- if (this == thatObject) {
- return true;
- } else if (thatObject == null || getClass() != thatObject.getClass()) {
- return false;
- }
-
- IMSIParameter that = (IMSIParameter) thatObject;
- return mPrefix == that.mPrefix && mImsi.equals(that.mImsi);
- }
-
- @Override
- public int hashCode() {
- int result = mImsi != null ? mImsi.hashCode() : 0;
- result = 31 * result + (mPrefix ? 1 : 0);
- return result;
- }
-
- @Override
- public String toString() {
- if (mPrefix) {
- return mImsi + '*';
- } else {
- return mImsi;
- }
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/OMADMAdapter.java b/packages/Osu/src/com/android/hotspot2/OMADMAdapter.java
deleted file mode 100644
index 1429b0b5b427..000000000000
--- a/packages/Osu/src/com/android/hotspot2/OMADMAdapter.java
+++ /dev/null
@@ -1,601 +0,0 @@
-package com.android.hotspot2;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.net.wifi.WifiManager;
-import android.os.SystemProperties;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.anqp.eap.EAP;
-import com.android.hotspot2.omadm.MOTree;
-import com.android.hotspot2.omadm.OMAConstants;
-import com.android.hotspot2.omadm.OMAConstructed;
-import com.android.hotspot2.osu.OSUManager;
-
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import static com.android.anqp.eap.NonEAPInnerAuth.NonEAPType;
-import static com.android.anqp.eap.NonEAPInnerAuth.mapInnerType;
-
-public class OMADMAdapter {
- private final Context mContext;
- private final String mImei;
- private final String mImsi;
- private final String mDevID;
- private final List<PathAccessor> mDevInfo;
- private final List<PathAccessor> mDevDetail;
-
- private static final int IMEI_Length = 14;
-
- private static final String[] ExtWiFiPath = {"DevDetail", "Ext", "org.wi-fi", "Wi-Fi"};
-
- private static final Map<String, String> RTProps = new HashMap<>();
-
- private MOTree mDevInfoTree;
- private MOTree mDevDetailTree;
-
- private static OMADMAdapter sInstance;
-
- static {
- RTProps.put(ExtWiFiPath[2], "urn:wfa:mo-ext:hotspot2dot0-devdetail-ext:1.0");
- }
-
- private static abstract class PathAccessor {
- private final String[] mPath;
- private final int mHashCode;
-
- protected PathAccessor(Object... path) {
- int length = 0;
- for (Object o : path) {
- if (o.getClass() == String[].class) {
- length += ((String[]) o).length;
- } else {
- length++;
- }
- }
- mPath = new String[length];
- int n = 0;
- for (Object o : path) {
- if (o.getClass() == String[].class) {
- for (String element : (String[]) o) {
- mPath[n++] = element;
- }
- } else if (o.getClass() == Integer.class) {
- mPath[n++] = "x" + o.toString();
- } else {
- mPath[n++] = o.toString();
- }
- }
- mHashCode = Arrays.hashCode(mPath);
- }
-
- @Override
- public int hashCode() {
- return mHashCode;
- }
-
- @Override
- public boolean equals(Object thatObject) {
- return thatObject == this || (thatObject instanceof ConstPathAccessor &&
- Arrays.equals(mPath, ((PathAccessor) thatObject).mPath));
- }
-
- private String[] getPath() {
- return mPath;
- }
-
- protected abstract Object getValue();
- }
-
- private static class ConstPathAccessor<T> extends PathAccessor {
- private final T mValue;
-
- protected ConstPathAccessor(T value, Object... path) {
- super(path);
- mValue = value;
- }
-
- protected Object getValue() {
- return mValue;
- }
- }
-
- public static OMADMAdapter getInstance(Context context) {
- synchronized (OMADMAdapter.class) {
- if (sInstance == null) {
- sInstance = new OMADMAdapter(context);
- }
- return sInstance;
- }
- }
-
- private OMADMAdapter(Context context) {
- mContext = context;
-
- TelephonyManager tm = (TelephonyManager) context
- .getSystemService(Context.TELEPHONY_SERVICE);
- String simOperator = tm.getSimOperator();
- mImsi = tm.getSubscriberId();
- mImei = tm.getImei();
- String strDevId;
-
- /* Use MEID for sprint */
- if ("310120".equals(simOperator) || (mImsi != null && mImsi.startsWith("310120"))) {
- /* MEID is 14 digits. If IMEI is returned as DevId, MEID can be extracted by taking
- * first 14 characters. This is not always true but should be the case for sprint */
- strDevId = tm.getDeviceId().toUpperCase(Locale.US);
- if (strDevId != null && strDevId.length() >= IMEI_Length) {
- strDevId = strDevId.substring(0, IMEI_Length);
- } else {
- Log.w(OSUManager.TAG, "MEID cannot be extracted from DeviceId " + strDevId);
- }
- } else {
- if (isPhoneTypeLTE()) {
- strDevId = mImei;
- } else {
- strDevId = tm.getDeviceId();
- }
- if (strDevId == null) {
- strDevId = "unknown";
- }
- strDevId = strDevId.toUpperCase(Locale.US);
-
- if (!isPhoneTypeLTE()) {
- strDevId = strDevId.substring(0, IMEI_Length);
- }
- }
- mDevID = strDevId;
-
- mDevInfo = new ArrayList<>();
- mDevInfo.add(new ConstPathAccessor<>(strDevId, "DevInfo", "DevID"));
- mDevInfo.add(new ConstPathAccessor<>(getProperty(context,
- "Man", "ro.product.manufacturer", "unknown"), "DevInfo", "Man"));
- mDevInfo.add(new ConstPathAccessor<>(getProperty(context,
- "Mod", "ro.product.model", "generic"), "DevInfo", "Mod"));
- mDevInfo.add(new ConstPathAccessor<>(getLocale(context), "DevInfo", "Lang"));
- mDevInfo.add(new ConstPathAccessor<>("1.2", "DevInfo", "DmV"));
-
- mDevDetail = new ArrayList<>();
- mDevDetail.add(new ConstPathAccessor<>(getDeviceType(), "DevDetail", "DevType"));
- mDevDetail.add(new ConstPathAccessor<>(SystemProperties.get("ro.product.brand"),
- "DevDetail", "OEM"));
- mDevDetail.add(new ConstPathAccessor<>(getVersion(context, false), "DevDetail", "FwV"));
- mDevDetail.add(new ConstPathAccessor<>(getVersion(context, true), "DevDetail", "SwV"));
- mDevDetail.add(new ConstPathAccessor<>(getHwV(), "DevDetail", "HwV"));
- mDevDetail.add(new ConstPathAccessor<>("TRUE", "DevDetail", "LrgObj"));
-
- mDevDetail.add(new ConstPathAccessor<>(32, "DevDetail", "URI", "MaxDepth"));
- mDevDetail.add(new ConstPathAccessor<>(2048, "DevDetail", "URI", "MaxTotLen"));
- mDevDetail.add(new ConstPathAccessor<>(64, "DevDetail", "URI", "MaxSegLen"));
-
- AtomicInteger index = new AtomicInteger(1);
- mDevDetail.add(new ConstPathAccessor<>(EAP.EAP_TTLS, ExtWiFiPath,
- "EAPMethodList", index, "EAPType"));
- mDevDetail.add(new ConstPathAccessor<>(mapInnerType(NonEAPType.MSCHAPv2), ExtWiFiPath,
- "EAPMethodList", index, "InnerMethod"));
-
- index.incrementAndGet();
- mDevDetail.add(new ConstPathAccessor<>(EAP.EAP_TTLS, ExtWiFiPath,
- "EAPMethodList", index, "EAPType"));
- mDevDetail.add(new ConstPathAccessor<>(mapInnerType(NonEAPType.PAP), ExtWiFiPath,
- "EAPMethodList", index, "InnerMethod"));
-
- index.incrementAndGet();
- mDevDetail.add(new ConstPathAccessor<>(EAP.EAP_TTLS, ExtWiFiPath,
- "EAPMethodList", index, "EAPType"));
- mDevDetail.add(new ConstPathAccessor<>(mapInnerType(NonEAPType.MSCHAP), ExtWiFiPath,
- "EAPMethodList", index, "InnerMethod"));
-
- index.incrementAndGet();
- mDevDetail.add(new ConstPathAccessor<>(EAP.EAP_TLS, ExtWiFiPath,
- "EAPMethodList", index, "EAPType"));
- index.incrementAndGet();
- mDevDetail.add(new ConstPathAccessor<>(EAP.EAP_AKA, ExtWiFiPath,
- "EAPMethodList", index, "EAPType"));
- index.incrementAndGet();
- mDevDetail.add(new ConstPathAccessor<>(EAP.EAP_AKAPrim, ExtWiFiPath,
- "EAPMethodList", index, "EAPType"));
- index.incrementAndGet();
- mDevDetail.add(new ConstPathAccessor<>(EAP.EAP_SIM, ExtWiFiPath,
- "EAPMethodList", index, "EAPType"));
-
- mDevDetail.add(new ConstPathAccessor<>("FALSE", ExtWiFiPath, "ManufacturingCertificate"));
- mDevDetail.add(new ConstPathAccessor<>(mImsi, ExtWiFiPath, "IMSI"));
- mDevDetail.add(new ConstPathAccessor<>(mImei, ExtWiFiPath, "IMEI_MEID"));
- mDevDetail.add(new PathAccessor(ExtWiFiPath, "Wi-FiMACAddress") {
- @Override
- protected String getValue() {
- return getMAC();
- }
- });
- }
-
- private static void buildNode(PathAccessor pathAccessor, int depth, OMAConstructed parent)
- throws IOException {
- String[] path = pathAccessor.getPath();
- String name = path[depth];
- if (depth < path.length - 1) {
- OMAConstructed node = (OMAConstructed) parent.getChild(name);
- if (node == null) {
- node = (OMAConstructed) parent.addChild(name, RTProps.get(name),
- null, null);
- }
- buildNode(pathAccessor, depth + 1, node);
- } else if (pathAccessor.getValue() != null) {
- parent.addChild(name, null, pathAccessor.getValue().toString(), null);
- }
- }
-
- public String getMAC() {
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- return wifiManager != null ?
- String.format("%012x",
- Utils.parseMac(wifiManager.getConnectionInfo().getMacAddress())) :
- null;
- }
-
- public String getImei() {
- return mImei;
- }
-
- public byte[] getMeid() {
- return Arrays.copyOf(mImei.getBytes(StandardCharsets.ISO_8859_1), IMEI_Length);
- }
-
- public String getDevID() {
- return mDevID;
- }
-
- public MOTree getMO(String urn) {
- try {
- switch (urn) {
- case OMAConstants.DevInfoURN:
- if (mDevInfoTree == null) {
- OMAConstructed root = new OMAConstructed(null, "DevInfo", urn);
- for (PathAccessor pathAccessor : mDevInfo) {
- buildNode(pathAccessor, 1, root);
- }
- mDevInfoTree = MOTree.buildMgmtTree(OMAConstants.DevInfoURN,
- OMAConstants.OMAVersion, root);
- }
- return mDevInfoTree;
- case OMAConstants.DevDetailURN:
- if (mDevDetailTree == null) {
- OMAConstructed root = new OMAConstructed(null, "DevDetail", urn);
- for (PathAccessor pathAccessor : mDevDetail) {
- buildNode(pathAccessor, 1, root);
- }
- mDevDetailTree = MOTree.buildMgmtTree(OMAConstants.DevDetailURN,
- OMAConstants.OMAVersion, root);
- }
- return mDevDetailTree;
- default:
- throw new IllegalArgumentException(urn);
- }
- } catch (IOException ioe) {
- Log.e(OSUManager.TAG, "Caught exception building OMA Tree: " + ioe, ioe);
- return null;
- }
-
- /*
- switch (urn) {
- case DevInfoURN: return DevInfo;
- case DevDetailURN: return DevDetail;
- default: throw new IllegalArgumentException(urn);
- }
- */
- }
-
- // TODO: For now, assume the device supports LTE.
- private static boolean isPhoneTypeLTE() {
- return true;
- }
-
- private static String getHwV() {
- try {
- return SystemProperties.get("ro.hardware", "Unknown")
- + "." + SystemProperties.get("ro.revision", "Unknown");
- } catch (RuntimeException e) {
- return "Unknown";
- }
- }
-
- private static String getDeviceType() {
- String devicetype = SystemProperties.get("ro.build.characteristics");
- if ((((TextUtils.isEmpty(devicetype)) || (!devicetype.equals("tablet"))))) {
- devicetype = "phone";
- }
- return devicetype;
- }
-
- private static String getVersion(Context context, boolean swv) {
- String version;
- try {
- if (!isSprint(context) && swv) {
- return "Android " + SystemProperties.get("ro.build.version.release");
- } else {
- version = SystemProperties.get("ro.build.version.full");
- if (null == version || version.equals("")) {
- return SystemProperties.get("ro.build.id", null) + "~"
- + SystemProperties.get("ro.build.config.version", null) + "~"
- + SystemProperties.get("gsm.version.baseband", null) + "~"
- + SystemProperties.get("ro.gsm.flexversion", null);
- }
- }
- } catch (RuntimeException e) {
- return "Unknown";
- }
- return version;
- }
-
- private static boolean isSprint(Context context) {
- TelephonyManager tm = (TelephonyManager) context
- .getSystemService(Context.TELEPHONY_SERVICE);
- String simOperator = tm.getSimOperator();
- String imsi = tm.getSubscriberId();
- /* Use MEID for sprint */
- if ("310120".equals(simOperator) || (imsi != null && imsi.startsWith("310120"))) {
- return true;
- } else {
- return false;
- }
- }
-
- private static String getLocale(Context context) {
- String strLang = readValueFromFile(context, "Lang");
- if (strLang == null) {
- strLang = Locale.getDefault().toString();
- }
- return strLang;
- }
-
- private static String getProperty(Context context, String key, String propKey, String dflt) {
- String strMan = readValueFromFile(context, key);
- if (strMan == null) {
- strMan = SystemProperties.get(propKey, dflt);
- }
- return strMan;
- }
-
- private static String readValueFromFile(Context context, String propName) {
- String ret = null;
- // use preference instead of the system property
- SharedPreferences prefs = context.getSharedPreferences("dmconfig", 0);
- if (prefs.contains(propName)) {
- ret = prefs.getString(propName, "");
- if (ret.length() == 0) {
- ret = null;
- }
- }
- return ret;
- }
-
- private static final String DevDetail =
- "<MgmtTree>" +
- "<VerDTD>1.2</VerDTD>" +
- "<Node>" +
- "<NodeName>DevDetail</NodeName>" +
- "<RTProperties>" +
- "<Type>" +
- "<DDFName>urn:oma:mo:oma-dm-devdetail:1.0</DDFName>" +
- "</Type>" +
- "</RTProperties>" +
- "<Node>" +
- "<NodeName>Ext</NodeName>" +
- "<Node>" +
- "<NodeName>org.wi-fi</NodeName>" +
- "<RTProperties>" +
- "<Type>" +
- "<DDFName>" +
- "urn:wfa:mo-ext:hotspot2dot0-devdetail-ext :1.0" +
- "</DDFName>" +
- "</Type>" +
- "</RTProperties>" +
- "<Node>" +
- "<NodeName>Wi-Fi</NodeName>" +
- "<Node>" +
- "<NodeName>EAPMethodList</NodeName>" +
- "<Node>" +
- "<NodeName>Method01</NodeName>" +
- "<!-- EAP-TTLS/MS-CHAPv2 -->" +
- "<Node>" +
- "<NodeName>EAPType</NodeName>" +
- "<Value>21</Value>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>InnerMethod</NodeName>" +
- "<Value>MS-CHAP-V2</Value>" +
- "</Node>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>Method02</NodeName>" +
- "<!-- EAP-TLS -->" +
- "<Node>" +
- "<NodeName>EAPType</NodeName>" +
- "<Value>13</Value>" +
- "</Node>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>Method03</NodeName>" +
- "<!-- EAP-SIM -->" +
- "<Node>" +
- "<NodeName>EAPType</NodeName>" +
- "<Value>18</Value>" +
- "</Node>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>Method04</NodeName>" +
- "<!-- EAP-AKA -->" +
- "<Node>" +
- "<NodeName>EAPType</NodeName>" +
- "<Value>23</Value>" +
- "</Node>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>Method05</NodeName>" +
- "<!-- EAP-AKA' -->" +
- "<Node>" +
- "<NodeName>EAPType</NodeName>" +
- "<Value>50</Value>" +
- "</Node>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>Method06</NodeName>" +
- "<!-- Supported method (EAP-TTLS/PAP) not mandated by Hotspot2.0-->" +
- "<Node>" +
- "<NodeName>EAPType</NodeName>" +
- "<Value>21</Value>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>InnerMethod</NodeName>" +
- "<Value>PAP</Value>" +
- "</Node>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>Method07</NodeName>" +
- "<!-- Supported method (PEAP/EAP-GTC) not mandated by Hotspot 2.0-->" +
- "<Node>" +
- "<NodeName>EAPType</NodeName>" +
- "<Value>25</Value>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>InnerEAPType</NodeName>" +
- "<Value>6</Value>" +
- "</Node>" +
- "</Node>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>SPCertificate</NodeName>" +
- "<Node>" +
- "<NodeName>Cert01</NodeName>" +
- "<Node>" +
- "<NodeName>CertificateIssuerName</NodeName>" +
- "<Value>CN=RuckusCA</Value>" +
- "</Node>" +
- "</Node>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>ManufacturingCertificate</NodeName>" +
- "<Value>FALSE</Value>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>Wi-FiMACAddress</NodeName>" +
- "<Value>001d2e112233</Value>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>ClientTriggerRedirectURI</NodeName>" +
- "<Value>http://127.0.0.1:12345/index.htm</Value>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>Ops</NodeName>" +
- "<Node>" +
- "<NodeName>launchBrowserToURI</NodeName>" +
- "<Value></Value>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>negotiateClientCertTLS</NodeName>" +
- "<Value></Value>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>getCertificate</NodeName>" +
- "<Value></Value>" +
- "</Node>" +
- "</Node>" +
- "</Node>" +
- "<!-- End of Wi-Fi node -->" +
- "</Node>" +
- "<!-- End of org.wi-fi node -->" +
- "</Node>" +
- "<!-- End of Ext node -->" +
- "<Node>" +
- "<NodeName>URI</NodeName>" +
- "<Node>" +
- "<NodeName>MaxDepth</NodeName>" +
- "<Value>32</Value>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>MaxTotLen</NodeName>" +
- "<Value>2048</Value>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>MaxSegLen</NodeName>" +
- "<Value>64</Value>" +
- "</Node>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>DevType</NodeName>" +
- "<Value>Smartphone</Value>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>OEM</NodeName>" +
- "<Value>ACME</Value>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>FwV</NodeName>" +
- "<Value>1.2.100.5</Value>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>SwV</NodeName>" +
- "<Value>9.11.130</Value>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>HwV</NodeName>" +
- "<Value>1.0</Value>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>LrgObj</NodeName>" +
- "<Value>TRUE</Value>" +
- "</Node>" +
- "</Node>" +
- "</MgmtTree>";
-
-
- private static final String DevInfo =
- "<MgmtTree>" +
- "<VerDTD>1.2</VerDTD>" +
- "<Node>" +
- "<NodeName>DevInfo</NodeName>" +
- "<RTProperties>" +
- "<Type>" +
- "<DDFName>urn:oma:mo:oma-dm-devinfo:1.0" +
- "</DDFName>" +
- "</Type>" +
- "</RTProperties>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>DevID</NodeName>" +
- "<Path>DevInfo</Path>" +
- "<Value>urn:acme:00-11-22-33-44-55</Value>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>Man</NodeName>" +
- "<Path>DevInfo</Path>" +
- "<Value>ACME</Value>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>Mod</NodeName>" +
- "<Path>DevInfo</Path>" +
- "<Value>HS2.0-01</Value>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>DmV</NodeName>" +
- "<Path>DevInfo</Path>" +
- "<Value>1.2</Value>" +
- "</Node>" +
- "<Node>" +
- "<NodeName>Lang</NodeName>" +
- "<Path>DevInfo</Path>" +
- "<Value>en-US</Value>" +
- "</Node>" +
- "</MgmtTree>";
-}
diff --git a/packages/Osu/src/com/android/hotspot2/PasspointMatch.java b/packages/Osu/src/com/android/hotspot2/PasspointMatch.java
deleted file mode 100644
index 8330283a7d2a..000000000000
--- a/packages/Osu/src/com/android/hotspot2/PasspointMatch.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.android.hotspot2;
-
-public enum PasspointMatch {
- HomeProvider,
- RoamingProvider,
- Incomplete,
- None,
- Declined
-}
diff --git a/packages/Osu/src/com/android/hotspot2/Utils.java b/packages/Osu/src/com/android/hotspot2/Utils.java
deleted file mode 100644
index 880007f6e392..000000000000
--- a/packages/Osu/src/com/android/hotspot2/Utils.java
+++ /dev/null
@@ -1,407 +0,0 @@
-package com.android.hotspot2;
-
-import com.android.anqp.Constants;
-
-import java.nio.ByteBuffer;
-import java.nio.charset.CharacterCodingException;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.TimeZone;
-
-import static com.android.anqp.Constants.BYTE_MASK;
-import static com.android.anqp.Constants.NIBBLE_MASK;
-
-public abstract class Utils {
-
- public static final long UNSET_TIME = -1;
-
- private static final int EUI48Length = 6;
- private static final int EUI64Length = 8;
- private static final long EUI48Mask = 0xffffffffffffL;
- private static final String[] PLMNText = {"org", "3gppnetwork", "mcc*", "mnc*", "wlan"};
-
- public static List<String> splitDomain(String domain) {
-
- if (domain.endsWith("."))
- domain = domain.substring(0, domain.length() - 1);
- int at = domain.indexOf('@');
- if (at >= 0)
- domain = domain.substring(at + 1);
-
- String[] labels = domain.toLowerCase().split("\\.");
- LinkedList<String> labelList = new LinkedList<String>();
- for (String label : labels) {
- labelList.addFirst(label);
- }
-
- return labelList;
- }
-
- public static long parseMac(String s) {
-
- long mac = 0;
- int count = 0;
- for (int n = 0; n < s.length(); n++) {
- int nibble = Utils.fromHex(s.charAt(n), true); // Set lenient to not blow up on ':'
- if (nibble >= 0) { // ... and use only legit hex.
- mac = (mac << 4) | nibble;
- count++;
- }
- }
- if (count < 12 || (count & 1) == 1) {
- throw new IllegalArgumentException("Bad MAC address: '" + s + "'");
- }
- return mac;
- }
-
- public static String macToString(long mac) {
- int len = (mac & ~EUI48Mask) != 0 ? EUI64Length : EUI48Length;
- StringBuilder sb = new StringBuilder();
- boolean first = true;
- for (int n = (len - 1) * Byte.SIZE; n >= 0; n -= Byte.SIZE) {
- if (first) {
- first = false;
- } else {
- sb.append(':');
- }
- sb.append(String.format("%02x", (mac >>> n) & Constants.BYTE_MASK));
- }
- return sb.toString();
- }
-
- public static String getMccMnc(List<String> domain) {
- if (domain.size() != PLMNText.length) {
- return null;
- }
-
- for (int n = 0; n < PLMNText.length; n++) {
- String expect = PLMNText[n];
- int len = expect.endsWith("*") ? expect.length() - 1 : expect.length();
- if (!domain.get(n).regionMatches(0, expect, 0, len)) {
- return null;
- }
- }
-
- String prefix = domain.get(2).substring(3) + domain.get(3).substring(3);
- for (int n = 0; n < prefix.length(); n++) {
- char ch = prefix.charAt(n);
- if (ch < '0' || ch > '9') {
- return null;
- }
- }
- return prefix;
- }
-
- public static String toIpString(int leIp) {
- return String.format("%d.%d.%d.%d",
- leIp & BYTE_MASK,
- (leIp >> 8) & BYTE_MASK,
- (leIp >> 16) & BYTE_MASK,
- (leIp >> 24) & BYTE_MASK);
- }
-
- public static String bssidsToString(Collection<Long> bssids) {
- StringBuilder sb = new StringBuilder();
- for (Long bssid : bssids) {
- sb.append(String.format(" %012x", bssid));
- }
- return sb.toString();
- }
-
- public static String roamingConsortiumsToString(long[] ois) {
- if (ois == null) {
- return "null";
- }
- List<Long> list = new ArrayList<Long>(ois.length);
- for (long oi : ois) {
- list.add(oi);
- }
- return roamingConsortiumsToString(list);
- }
-
- public static String roamingConsortiumsToString(Collection<Long> ois) {
- StringBuilder sb = new StringBuilder();
- boolean first = true;
- for (long oi : ois) {
- if (first) {
- first = false;
- } else {
- sb.append(", ");
- }
- if (Long.numberOfLeadingZeros(oi) > 40) {
- sb.append(String.format("%06x", oi));
- } else {
- sb.append(String.format("%010x", oi));
- }
- }
- return sb.toString();
- }
-
- public static String toUnicodeEscapedString(String s) {
- StringBuilder sb = new StringBuilder(s.length());
- for (int n = 0; n < s.length(); n++) {
- char ch = s.charAt(n);
- if (ch >= ' ' && ch < 127) {
- sb.append(ch);
- } else {
- sb.append("\\u").append(String.format("%04x", (int) ch));
- }
- }
- return sb.toString();
- }
-
- public static String toHexString(byte[] data) {
- if (data == null) {
- return "null";
- }
- StringBuilder sb = new StringBuilder(data.length * 3);
-
- boolean first = true;
- for (byte b : data) {
- if (first) {
- first = false;
- } else {
- sb.append(' ');
- }
- sb.append(String.format("%02x", b & BYTE_MASK));
- }
- return sb.toString();
- }
-
- public static String toHex(byte[] octets) {
- StringBuilder sb = new StringBuilder(octets.length * 2);
- for (byte o : octets) {
- sb.append(String.format("%02x", o & BYTE_MASK));
- }
- return sb.toString();
- }
-
- public static byte[] hexToBytes(String text) {
- if ((text.length() & 1) == 1) {
- throw new NumberFormatException("Odd length hex string: " + text.length());
- }
- byte[] data = new byte[text.length() >> 1];
- int position = 0;
- for (int n = 0; n < text.length(); n += 2) {
- data[position] =
- (byte) (((fromHex(text.charAt(n), false) & NIBBLE_MASK) << 4) |
- (fromHex(text.charAt(n + 1), false) & NIBBLE_MASK));
- position++;
- }
- return data;
- }
-
- public static int fromHex(char ch, boolean lenient) throws NumberFormatException {
- if (ch <= '9' && ch >= '0') {
- return ch - '0';
- } else if (ch >= 'a' && ch <= 'f') {
- return ch + 10 - 'a';
- } else if (ch <= 'F' && ch >= 'A') {
- return ch + 10 - 'A';
- } else if (lenient) {
- return -1;
- } else {
- throw new NumberFormatException("Bad hex-character: " + ch);
- }
- }
-
- private static char toAscii(int b) {
- return b >= ' ' && b < 0x7f ? (char) b : '.';
- }
-
- static boolean isDecimal(String s) {
- for (int n = 0; n < s.length(); n++) {
- char ch = s.charAt(n);
- if (ch < '0' || ch > '9') {
- return false;
- }
- }
- return true;
- }
-
- public static <T extends Comparable> int compare(Comparable<T> c1, T c2) {
- if (c1 == null) {
- return c2 == null ? 0 : -1;
- } else if (c2 == null) {
- return 1;
- } else {
- return c1.compareTo(c2);
- }
- }
-
- public static String bytesToBingoCard(ByteBuffer data, int len) {
- ByteBuffer dup = data.duplicate();
- dup.limit(dup.position() + len);
- return bytesToBingoCard(dup);
- }
-
- public static String bytesToBingoCard(ByteBuffer data) {
- ByteBuffer dup = data.duplicate();
- StringBuilder sbx = new StringBuilder();
- while (dup.hasRemaining()) {
- sbx.append(String.format("%02x ", dup.get() & BYTE_MASK));
- }
- dup = data.duplicate();
- sbx.append(' ');
- while (dup.hasRemaining()) {
- sbx.append(String.format("%c", toAscii(dup.get() & BYTE_MASK)));
- }
- return sbx.toString();
- }
-
- public static String toHMS(long millis) {
- long time = millis >= 0 ? millis : -millis;
- long tmp = time / 1000L;
- long ms = time - tmp * 1000L;
-
- time = tmp;
- tmp /= 60L;
- long s = time - tmp * 60L;
-
- time = tmp;
- tmp /= 60L;
- long m = time - tmp * 60L;
-
- return String.format("%s%d:%02d:%02d.%03d", millis < 0 ? "-" : "", tmp, m, s, ms);
- }
-
- public static String toUTCString(long ms) {
- if (ms < 0) {
- return "unset";
- }
- Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- c.setTimeInMillis(ms);
- return String.format("%4d/%02d/%02d %2d:%02d:%02dZ",
- c.get(Calendar.YEAR),
- c.get(Calendar.MONTH) + 1,
- c.get(Calendar.DAY_OF_MONTH),
- c.get(Calendar.HOUR_OF_DAY),
- c.get(Calendar.MINUTE),
- c.get(Calendar.SECOND));
- }
-
- /**
- * Decode a wpa_supplicant SSID. wpa_supplicant uses double quotes around plain strings, or
- * expects a hex-string if no quotes appear.
- * For Ascii encoded string, any octet < 32 or > 127 is encoded as
- * a "\x" followed by the hex representation of the octet.
- * Exception chars are ", \, \e, \n, \r, \t which are escaped by a \
- * See src/utils/common.c for the implementation in the supplicant.
- *
- * @param ssid The SSID from the config.
- * @return The actual string content of the SSID
- */
- public static String decodeSsid(String ssid) {
- if (ssid.length() <= 1) {
- return ssid;
- } else if (ssid.startsWith("\"") && ssid.endsWith("\"")) {
- return unescapeSsid(ssid.substring(1, ssid.length() - 1));
- } else if ((ssid.length() & 1) == 1) {
- return ssid;
- }
-
- byte[] codepoints;
- try {
- codepoints = new byte[ssid.length() / 2];
- for (int n = 0; n < ssid.length(); n += 2) {
- codepoints[n / 2] = (byte) decodeHexPair(ssid, n);
- }
- } catch (NumberFormatException nfe) {
- return ssid;
- }
-
- try {
- CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
- return decoder.decode(ByteBuffer.wrap(codepoints)).toString();
- } catch (CharacterCodingException cce) {
- /* Do nothing, try LATIN-1 */
- }
- try {
- CharsetDecoder decoder = StandardCharsets.ISO_8859_1.newDecoder();
- return decoder.decode(ByteBuffer.wrap(codepoints)).toString();
- } catch (CharacterCodingException cce) { // Should not be possible.
- return ssid;
- }
- }
-
- private static String unescapeSsid(String s) {
- StringBuilder sb = new StringBuilder();
- for (int n = 0; n < s.length(); n++) {
- char ch = s.charAt(n);
- if (ch != '\\' || n >= s.length() - 1) {
- sb.append(ch);
- } else {
- n++;
- ch = s.charAt(n);
- switch (ch) {
- case '"':
- case '\\':
- default:
- sb.append(ch);
- break;
- case 'e':
- sb.append((char) 27); // Escape char
- break;
- case 'n':
- sb.append('\n');
- break;
- case 'r':
- sb.append('\r');
- break;
- case 't':
- sb.append('\t');
- break;
- case 'x':
- if (s.length() - n < 3) {
- sb.append('\\').append(ch);
- } else {
- n++;
- sb.append((char) decodeHexPair(s, n));
- n++;
- }
- break;
- }
- }
- }
- return sb.toString();
- }
-
- private static int decodeHexPair(String s, int position) {
- return fromHex(s.charAt(position)) << 4 | fromHex(s.charAt(position + 1));
- }
-
- private static int fromHex(char ch) {
- if (ch >= '0' && ch <= '9') {
- return ch - '0';
- } else if (ch >= 'A' && ch <= 'F') {
- return ch - 'A' + 10;
- } else if (ch >= 'a' && ch <= 'f') {
- return ch - 'a' + 10;
- } else {
- throw new NumberFormatException(String.format("Not hex: '%c'", ch));
- }
- }
-
- public static void delay(long ms) {
- long until = System.currentTimeMillis() + ms;
- for (; ; ) {
- long remainder = until - System.currentTimeMillis();
- if (remainder <= 0) {
- break;
- }
- try {
- Thread.sleep(remainder);
- } catch (InterruptedException ie) { /**/ }
- }
- }
-
- public static <T extends Enum<T>> T mapEnum(int ordinal, Class<T> enumClass) {
- T[] constants = enumClass.getEnumConstants();
- return ordinal >= 0 && ordinal < constants.length ? constants[ordinal]: null;
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/app/IOSUAccessor.aidl b/packages/Osu/src/com/android/hotspot2/app/IOSUAccessor.aidl
deleted file mode 100644
index 500dd2ee32c4..000000000000
--- a/packages/Osu/src/com/android/hotspot2/app/IOSUAccessor.aidl
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.android.hotspot2.app;
-
-import com.android.hotspot2.app.OSUData;
-
-interface IOSUAccessor {
- List<OSUData> getOsuData();
- void selectOsu(int id);
-}
diff --git a/packages/Osu/src/com/android/hotspot2/app/LocalServiceBinder.java b/packages/Osu/src/com/android/hotspot2/app/LocalServiceBinder.java
deleted file mode 100644
index 8801839fe262..000000000000
--- a/packages/Osu/src/com/android/hotspot2/app/LocalServiceBinder.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.android.hotspot2.app;
-
-import android.os.Binder;
-
-public class LocalServiceBinder extends Binder {
- private final OSUService mDelegate;
-
- public LocalServiceBinder(OSUService delegate) {
- mDelegate = delegate;
- }
-
- public OSUService getService() {
- return mDelegate;
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/app/MainActivity.java b/packages/Osu/src/com/android/hotspot2/app/MainActivity.java
deleted file mode 100644
index 7fd2238703f1..000000000000
--- a/packages/Osu/src/com/android/hotspot2/app/MainActivity.java
+++ /dev/null
@@ -1,303 +0,0 @@
-package com.android.hotspot2.app;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.TaskStackBuilder;
-import android.content.ComponentName;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.graphics.BitmapFactory;
-import android.graphics.drawable.BitmapDrawable;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import com.android.hotspot2.AppBridge;
-import com.android.hotspot2.R;
-import com.android.hotspot2.osu.OSUManager;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Main activity.
- */
-public class MainActivity extends Activity {
- private static final int NOTIFICATION_ID = 0; // Used for OSU count
- private static final int NOTIFICATION_MESSAGE_ID = 1; // Used for other messages
- private static final String ACTION_SVC_BOUND = "SVC_BOUND";
-
- private volatile OSUService mLocalService;
-
- private final ServiceConnection mConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- LocalServiceBinder binder = (LocalServiceBinder) service;
- mLocalService = binder.getService();
- showOsuSelection(mLocalService);
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- mLocalService = null;
- }
- };
-
- private ListView osuListView;
- private OsuListAdapter osuListAdapter;
- private String message;
-
- public MainActivity() {
-
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- if (mLocalService != null) {
- unbindService(mConnection);
- mLocalService = null;
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- if (message != null) {
- showDialog(message);
- message = null;
- }
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- final Intent intent = getIntent();
- Bundle bundle = intent.getExtras();
-
- if (intent.getAction() == null) {
- if (mLocalService == null) {
- bindService(new Intent(this, OSUService.class), mConnection, 0);
- }
- } else if (intent.getAction().equals(AppBridge.ACTION_OSU_NOTIFICATION)) {
- if (bundle == null) {
- Log.d(OSUManager.TAG, "No parameters for OSU notification");
- return;
- }
- if (bundle.containsKey(AppBridge.OSU_COUNT)) {
- showOsuCount(bundle.getInt("osu-count", 0), Collections.<OSUData>emptyList());
- } else if (bundle.containsKey(AppBridge.PROV_SUCCESS)) {
- showStatus(bundle.getBoolean(AppBridge.PROV_SUCCESS),
- bundle.getString(AppBridge.SP_NAME),
- bundle.getString(AppBridge.PROV_MESSAGE),
- null);
- } else if (bundle.containsKey(AppBridge.DEAUTH)) {
- showDeauth(bundle.getString(AppBridge.SP_NAME),
- bundle.getBoolean(AppBridge.DEAUTH),
- bundle.getInt(AppBridge.DEAUTH_DELAY),
- bundle.getString(AppBridge.DEAUTH_URL));
- }
- }
- }
-
- private void showOsuSelection(final OSUService osuService) {
- List<OSUData> osuData = osuService.getOsuData();
-
- setContentView(R.layout.activity_main);
- Log.d("osu", "osu count:" + osuData.size());
- View noOsuView = findViewById(R.id.no_osu);
- if (osuData.size() > 0) {
- noOsuView.setVisibility(View.GONE);
- osuListAdapter = new OsuListAdapter(this, osuData);
- osuListView = findViewById(R.id.profile_list);
- osuListView.setAdapter(osuListAdapter);
- osuListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
- OSUData osuData = (OSUData) adapterView.getAdapter().getItem(position);
- Log.d("osu", "launch osu:" + osuData.getName()
- + " id:" + osuData.getId());
- osuService.selectOsu(osuData.getId());
- finish();
- }
- });
- } else {
- noOsuView.setVisibility(View.VISIBLE);
- }
- }
-
- private void showOsuCount(int osuCount, List<OSUData> osus) {
- if (osuCount > 0) {
- printOsuDataList(osus);
- sendNotification(osuCount);
- } else {
- cancelNotification();
- }
- finish();
- }
-
- private void showStatus(boolean provSuccess, String spName, String provMessage,
- String remoteStatus) {
- if (provSuccess) {
- sendDialogMessage(
- String.format("Credentials for %s was successfully installed", spName));
- } else {
- if (spName != null) {
- if (remoteStatus != null) {
- sendDialogMessage(
- String.format("Failed to install credentials for %s: %s: %s",
- spName, provMessage, remoteStatus));
- } else {
- sendDialogMessage(
- String.format("Failed to install credentials for %s: %s",
- spName, provMessage));
- }
- } else {
- sendDialogMessage(
- String.format("Failed to contact OSU: %s", provMessage));
- }
- }
- }
-
- private void showDeauth(String spName, boolean ess, int delay, String url) {
- String delayReadable = getReadableTimeInSeconds(delay);
- if (ess) {
- if (delay > 60) {
- sendDialogMessage(
- String.format("There is an issue connecting to %s [for the next %s]. " +
- "Please visit %s for details", spName, delayReadable, url));
- } else {
- sendDialogMessage(
- String.format("There is an issue connecting to %s. " +
- "Please visit %s for details", spName, url));
- }
- } else {
- sendDialogMessage(
- String.format("There is an issue with the closest Access Point for %s. " +
- "You may wait %s or move to another Access Point to " +
- "regain access. Please visit %s for details.",
- spName, delayReadable, url));
- }
- }
-
- private String getReadableTimeInSeconds(int timeSeconds) {
- long hours = TimeUnit.SECONDS.toHours(timeSeconds);
- long minutes = TimeUnit.SECONDS.toMinutes(timeSeconds) - TimeUnit.HOURS.toMinutes(hours);
- long seconds =
- timeSeconds - TimeUnit.HOURS.toSeconds(hours) - TimeUnit.MINUTES.toSeconds(minutes);
- if (hours > 0) {
- return String.format("%02d:%02d:%02d", hours, minutes, seconds);
- } else {
- return String.format("%ds", seconds);
- }
- }
-
- private void sendNotification(int count) {
- Notification.Builder builder =
- new Notification.Builder(this)
- .setContentTitle(String.format("%s OSU available", count))
- .setContentText("Choose one to connect")
- .setSmallIcon(android.R.drawable.ic_dialog_info)
- .setAutoCancel(false);
- Intent resultIntent = new Intent(this, MainActivity.class);
-
- TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
- stackBuilder.addParentStack(MainActivity.class);
- stackBuilder.addNextIntent(resultIntent);
- PendingIntent resultPendingIntent =
- stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
- builder.setContentIntent(resultPendingIntent);
- NotificationManager notificationManager =
- (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
- notificationManager.notify(NOTIFICATION_ID, builder.build());
- }
-
- private void cancelNotification() {
- NotificationManager notificationManager =
- (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
- notificationManager.cancel(NOTIFICATION_ID);
- }
-
- private void sendDialogMessage(String message) {
-// sendNotificationMessage(message);
- this.message = message;
- }
-
- private void showDialog(String message) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setMessage(message)
- .setTitle("OSU");
- builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialogInterface) {
- dialogInterface.cancel();
- finish();
- }
- });
- AlertDialog dialog = builder.create();
- dialog.show();
- }
-
- private void sendNotificationMessage(String title) {
- Notification.Builder builder =
- new Notification.Builder(this)
- .setContentTitle(title)
- .setContentText("Click to dismiss.")
- .setSmallIcon(android.R.drawable.ic_dialog_info)
- .setAutoCancel(true);
- NotificationManager notificationManager =
- (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
- notificationManager.notify(NOTIFICATION_MESSAGE_ID, builder.build());
- }
-
- private static class OsuListAdapter extends ArrayAdapter<OSUData> {
- private Activity activity;
-
- public OsuListAdapter(Activity activity, List<OSUData> osuDataList) {
- super(activity, R.layout.list_item, osuDataList);
- this.activity = activity;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View view = convertView;
- if (view == null) {
- view = LayoutInflater.from(getContext()).inflate(R.layout.list_item, parent, false);
- }
- OSUData osuData = getItem(position);
- TextView osuName = (TextView) view.findViewById(R.id.profile_name);
- osuName.setText(osuData.getName());
- TextView osuDetail = (TextView) view.findViewById(R.id.profile_detail);
- osuDetail.setText(osuData.getServiceDescription());
- ImageView osuIcon = (ImageView) view.findViewById(R.id.profile_logo);
- byte[] iconData = osuData.getIconData();
- osuIcon.setImageDrawable(
- new BitmapDrawable(activity.getResources(),
- BitmapFactory.decodeByteArray(iconData, 0, iconData.length)));
- return view;
- }
- }
-
- private void printOsuDataList(List<OSUData> osuDataList) {
- for (OSUData osuData : osuDataList) {
- Log.d("osu", String.format("OSUData:[%s][%s][%d]",
- osuData.getName(), osuData.getServiceDescription(),
- osuData.getId()));
- }
- }
-
-}
diff --git a/packages/Osu/src/com/android/hotspot2/app/OSUData.aidl b/packages/Osu/src/com/android/hotspot2/app/OSUData.aidl
deleted file mode 100644
index 3407f47cbd62..000000000000
--- a/packages/Osu/src/com/android/hotspot2/app/OSUData.aidl
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.android.hotspot2.app;
-
-parcelable OSUData;
-
diff --git a/packages/Osu/src/com/android/hotspot2/app/OSUData.java b/packages/Osu/src/com/android/hotspot2/app/OSUData.java
deleted file mode 100644
index 17cc49b77334..000000000000
--- a/packages/Osu/src/com/android/hotspot2/app/OSUData.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package com.android.hotspot2.app;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.hotspot2.flow.OSUInfo;
-import com.android.hotspot2.osu.OSUManager;
-
-public class OSUData implements Parcelable {
- private final String mName;
- private final String mServiceDescription;
- private final byte[] mIconData;
- private final int mId;
-
- public OSUData(OSUInfo osuInfo) {
- mName = osuInfo.getName(OSUManager.LOCALE);
- mServiceDescription = osuInfo.getServiceDescription(OSUManager.LOCALE);
- mIconData = osuInfo.getIconFileElement().getIconData();
- mId = osuInfo.getOsuID();
- }
-
- public String getName() {
- return mName;
- }
-
- public String getServiceDescription() {
- return mServiceDescription;
- }
-
- public byte[] getIconData() {
- return mIconData;
- }
-
- public int getId() {
- return mId;
- }
-
- private OSUData(Parcel in) {
- mName = in.readString();
- mServiceDescription = in.readString();
- int iconSize = in.readInt();
- mIconData = new byte[iconSize];
- in.readByteArray(mIconData);
- mId = in.readInt();
- }
-
- public static final Parcelable.Creator<OSUData> CREATOR = new Parcelable.Creator<OSUData>() {
- public OSUData createFromParcel(Parcel in) {
- return new OSUData(in);
- }
-
- public OSUData[] newArray(int size) {
- return new OSUData[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mName);
- dest.writeString(mServiceDescription);
- dest.writeByteArray(mIconData);
- dest.writeInt(mId);
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/app/OSUService.java b/packages/Osu/src/com/android/hotspot2/app/OSUService.java
deleted file mode 100644
index e9da113af747..000000000000
--- a/packages/Osu/src/com/android/hotspot2/app/OSUService.java
+++ /dev/null
@@ -1,206 +0,0 @@
-package com.android.hotspot2.app;
-
-import android.app.IntentService;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.util.Log;
-
-import com.android.anqp.OSUProvider;
-import com.android.hotspot2.PasspointMatch;
-import com.android.hotspot2.osu.OSUManager;
-
-import java.io.IOException;
-import java.util.List;
-
-/**
- * This is the Hotspot 2.0 release 2 OSU background service that is continuously running and caches
- * OSU information.
- *
- * The OSU App is made up of two services; FlowService and OSUService.
- *
- * OSUService is a long running light weight service, kept alive throughout the lifetime of the
- * operating system by being bound from the framework (in WifiManager in stage
- * PHASE_THIRD_PARTY_APPS_CAN_START), and is responsible for continuously caching OSU information
- * and notifying the UI when OSUs are available.
- *
- * FlowService is only started on demand from OSUService and is responsible for handling actual
- * provisioning and remediation flows, and requires a fairly significant memory footprint.
- *
- * FlowService is defined to run in its own process through the definition
- * <service android:name=".flow.FlowService" android:process=":osuflow">
- * in the AndroidManifest.
- * This is done as a means to keep total app memory footprint low (pss < 10M) and only start the
- * FlowService on demand and make it available for "garbage collection" by the OS when not in use.
- */
-public class OSUService extends IntentService {
- public static final String REMEDIATION_DONE_ACTION = "com.android.hotspot2.REMEDIATION_DONE";
- public static final String REMEDIATION_FQDN_EXTRA = "com.android.hotspot2.REMEDIATION_FQDN";
- public static final String REMEDIATION_POLICY_EXTRA = "com.android.hotspot2.REMEDIATION_POLICY";
-
- private static final String[] INTENTS = {
- WifiManager.SCAN_RESULTS_AVAILABLE_ACTION,
- // TODO(b/32883320): use updated intent definitions.
- //WifiManager.PASSPOINT_WNM_FRAME_RECEIVED_ACTION,
- //WifiManager.PASSPOINT_ICON_RECEIVED_ACTION,
- WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION,
- WifiManager.WIFI_STATE_CHANGED_ACTION,
- WifiManager.NETWORK_STATE_CHANGED_ACTION,
- REMEDIATION_DONE_ACTION
- };
-
- private OSUManager mOsuManager;
- private final LocalServiceBinder mLocalServiceBinder;
-
- public OSUService() {
- super("OSUService");
- mLocalServiceBinder = new LocalServiceBinder(this);
- }
-
- /*
- public final class OSUAccessorImpl extends IOSUAccessor.Stub {
- public List<OSUData> getOsuData() {
- List<OSUInfo> infos = getOsuInfos();
- List<OSUData> data = new ArrayList<>(infos.size());
- for (OSUInfo osuInfo : infos) {
- data.add(new OSUData(osuInfo));
- }
- return data;
- }
-
- public void selectOsu(int id) {
- OSUService.this.selectOsu(id);
- }
- }
- */
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- onHandleIntent(intent);
- return START_STICKY;
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- BroadcastReceiver receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- handleIntent(intent.getAction(), intent);
- }
- };
- for (String intentString : INTENTS) {
- registerReceiver(receiver, new IntentFilter(intentString));
- }
- return mLocalServiceBinder;
- }
-
- @Override
- protected void onHandleIntent(Intent intent) {
- if (intent == null) {
- Log.d(OSUManager.TAG, "Null intent!");
- return;
- }
- //handleIntent(intent.getStringExtra(MainActivity.ACTION_KEY), intent);
- }
-
- private void handleIntent(String action, Intent intent) {
- WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
- Bundle bundle = intent.getExtras();
- if (mOsuManager == null) {
- mOsuManager = new OSUManager(this);
- }
- Log.d(OSUManager.TAG, "Got intent " + intent.getAction());
-
- switch (action) {
- case WifiManager.SCAN_RESULTS_AVAILABLE_ACTION:
- mOsuManager.pushScanResults(wifiManager.getScanResults());
- break;
- // TODO(b/32883320): use updated intent definitions.
- /*
- case WifiManager.PASSPOINT_WNM_FRAME_RECEIVED_ACTION:
- long bssid = bundle.getLong(WifiManager.EXTRA_PASSPOINT_WNM_BSSID);
- String url = bundle.getString(WifiManager.EXTRA_PASSPOINT_WNM_URL);
-
- try {
- if (bundle.containsKey(WifiManager.EXTRA_PASSPOINT_WNM_METHOD)) {
- int method = bundle.getInt(WifiManager.EXTRA_PASSPOINT_WNM_METHOD);
- if (method != OSUProvider.OSUMethod.SoapXml.ordinal()) {
- Log.w(OSUManager.TAG, "Unsupported remediation method: " + method);
- return;
- }
- PasspointMatch match = null;
- if (bundle.containsKey(WifiManager.EXTRA_PASSPOINT_WNM_PPOINT_MATCH)) {
- int ordinal =
- bundle.getInt(WifiManager.EXTRA_PASSPOINT_WNM_PPOINT_MATCH);
- if (ordinal >= 0 && ordinal < PasspointMatch.values().length) {
- match = PasspointMatch.values()[ordinal];
- }
- }
- mOsuManager.wnmRemediate(bssid, url, match);
- } else if (bundle.containsKey(WifiManager.EXTRA_PASSPOINT_WNM_ESS)) {
- boolean ess = bundle.getBoolean(WifiManager.EXTRA_PASSPOINT_WNM_ESS);
- int delay = bundle.getInt(WifiManager.EXTRA_PASSPOINT_WNM_DELAY);
- mOsuManager.deauth(bssid, ess, delay, url);
- } else {
- Log.w(OSUManager.TAG, "Unknown WNM event");
- }
- } catch (IOException e) {
- Log.w(OSUManager.TAG, "Remediation event failed to parse: " + e);
- }
- break;
- case WifiManager.PASSPOINT_ICON_RECEIVED_ACTION:
- mOsuManager.notifyIconReceived(
- bundle.getLong(WifiManager.EXTRA_PASSPOINT_ICON_BSSID),
- bundle.getString(WifiManager.EXTRA_PASSPOINT_ICON_FILE),
- bundle.getByteArray(WifiManager.EXTRA_PASSPOINT_ICON_DATA));
- break;
- */
- case WifiManager.NETWORK_STATE_CHANGED_ACTION:
- mOsuManager.networkConnectChange(
- (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO));
- break;
- case WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION:
- boolean multiNetwork =
- bundle.getBoolean(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, false);
- if (multiNetwork) {
- mOsuManager.networkConfigChanged();
- } else if (bundle.getInt(WifiManager.EXTRA_CHANGE_REASON,
- WifiManager.CHANGE_REASON_CONFIG_CHANGE)
- == WifiManager.CHANGE_REASON_REMOVED) {
- WifiConfiguration configuration =
- intent.getParcelableExtra(WifiManager.EXTRA_WIFI_CONFIGURATION);
- mOsuManager.networkDeleted(configuration);
- } else {
- mOsuManager.networkConfigChanged();
- }
- break;
- case WifiManager.WIFI_STATE_CHANGED_ACTION:
- int state = bundle.getInt(WifiManager.EXTRA_WIFI_STATE);
- if (state == WifiManager.WIFI_STATE_DISABLED) {
- mOsuManager.wifiStateChange(false);
- } else if (state == WifiManager.WIFI_STATE_ENABLED) {
- mOsuManager.wifiStateChange(true);
- }
- break;
- case REMEDIATION_DONE_ACTION:
- String fqdn = bundle.getString(REMEDIATION_FQDN_EXTRA);
- boolean policy = bundle.getBoolean(REMEDIATION_POLICY_EXTRA);
- mOsuManager.remediationDone(fqdn, policy);
- break;
- }
- }
-
- public List<OSUData> getOsuData() {
- return mOsuManager.getAvailableOSUs();
- }
-
- public void selectOsu(int id) {
- mOsuManager.setOSUSelection(id);
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/asn1/Asn1Boolean.java b/packages/Osu/src/com/android/hotspot2/asn1/Asn1Boolean.java
deleted file mode 100644
index 18af3b80f7c4..000000000000
--- a/packages/Osu/src/com/android/hotspot2/asn1/Asn1Boolean.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.android.hotspot2.asn1;
-
-import java.nio.ByteBuffer;
-import java.util.Collection;
-
-public class Asn1Boolean extends Asn1Object {
- private final boolean mBoolean;
-
- public Asn1Boolean(int tag, Asn1Class asn1Class, int length, ByteBuffer data)
- throws DecodeException {
- super(tag, asn1Class, false, length);
- if (length != 1) {
- throw new DecodeException("Boolean length != 1: " + length, data.position());
- }
- mBoolean = data.get() != 0;
- }
-
- public boolean getValue() {
- return mBoolean;
- }
-
- @Override
- public Collection<Asn1Object> getChildren() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String toString() {
- return super.toString() + "=" + Boolean.toString(mBoolean);
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/asn1/Asn1Class.java b/packages/Osu/src/com/android/hotspot2/asn1/Asn1Class.java
deleted file mode 100644
index 8a4d8a803245..000000000000
--- a/packages/Osu/src/com/android/hotspot2/asn1/Asn1Class.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.android.hotspot2.asn1;
-
-public enum Asn1Class {
- Universal, Application, Context, Private
-}
diff --git a/packages/Osu/src/com/android/hotspot2/asn1/Asn1Constructed.java b/packages/Osu/src/com/android/hotspot2/asn1/Asn1Constructed.java
deleted file mode 100644
index 69b65dcd241a..000000000000
--- a/packages/Osu/src/com/android/hotspot2/asn1/Asn1Constructed.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.android.hotspot2.asn1;
-
-import java.nio.ByteBuffer;
-import java.util.*;
-
-public class Asn1Constructed extends Asn1Object {
- private final int mTagPosition;
- private final List<Asn1Object> mChildren;
-
- public Asn1Constructed(int tag, Asn1Class asn1Class, int length,
- ByteBuffer payload, int tagPosition) {
- super(tag, asn1Class, true, length, payload);
- mTagPosition = tagPosition;
- mChildren = new ArrayList<>();
- }
-
- public void addChild(Asn1Object object) {
- mChildren.add(object);
- }
-
- @Override
- public Collection<Asn1Object> getChildren() {
- return Collections.unmodifiableCollection(mChildren);
- }
-
- public ByteBuffer getEncoding() {
- return getPayload(mTagPosition);
- }
-
- private void toString(int level, StringBuilder sb) {
- sb.append(indent(level)).append(super.toString()).append(":\n");
- for (Asn1Object child : mChildren) {
- if (child.isConstructed()) {
- ((Asn1Constructed) child).toString(level + 1, sb);
- } else {
- sb.append(indent(level + 1)).append(child.toString()).append('\n');
- }
- }
- }
-
- public static String indent(int level) {
- char[] indent = new char[level * 2];
- Arrays.fill(indent, ' ');
- return new String(indent);
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- toString(0, sb);
- return sb.toString();
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/asn1/Asn1Decoder.java b/packages/Osu/src/com/android/hotspot2/asn1/Asn1Decoder.java
deleted file mode 100644
index 53452e79ab15..000000000000
--- a/packages/Osu/src/com/android/hotspot2/asn1/Asn1Decoder.java
+++ /dev/null
@@ -1,211 +0,0 @@
-package com.android.hotspot2.asn1;
-
-import java.nio.ByteBuffer;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-public class Asn1Decoder {
- public static final int TAG_UNIVZERO = 0x00;
- public static final int TAG_BOOLEAN = 0x01;
- public static final int TAG_INTEGER = 0x02;
- public static final int TAG_BITSTRING = 0x03;
- public static final int TAG_OCTET_STRING = 0x04;
- public static final int TAG_NULL = 0x05;
- public static final int TAG_OID = 0x06;
- public static final int TAG_ObjectDescriptor = 0x07;
- public static final int TAG_EXTERNAL = 0x08;
- public static final int TAG_REAL = 0x09;
- public static final int TAG_ENUMERATED = 0x0a;
- public static final int TAG_UTF8String = 0x0c; // * (*) are X.509 DirectoryString's
- public static final int TAG_RelativeOID = 0x0d;
- public static final int TAG_SEQ = 0x10; // 30 if constructed
- public static final int TAG_SET = 0x11;
- public static final int TAG_NumericString = 0x12; // [UNIVERSAL 18]
- public static final int TAG_PrintableString = 0x13; // * [UNIVERSAL 19]
- public static final int TAG_T61String = 0x14; // * TeletexString [UNIVERSAL 20]
- public static final int TAG_VideotexString = 0x15; // [UNIVERSAL 21]
- public static final int TAG_IA5String = 0x16; // [UNIVERSAL 22]
- public static final int TAG_UTCTime = 0x17;
- public static final int TAG_GeneralizedTime = 0x18;
- public static final int TAG_GraphicString = 0x19; // [UNIVERSAL 25]
- public static final int TAG_VisibleString = 0x1a; // ISO64String [UNIVERSAL 26]
- public static final int TAG_GeneralString = 0x1b; // [UNIVERSAL 27]
- public static final int TAG_UniversalString = 0x1c; // * [UNIVERSAL 28]
- public static final int TAG_BMPString = 0x1e; // * [UNIVERSAL 30]
-
- public static final int IntOverflow = 0xffff0000;
- public static final int MoreBit = 0x80;
- public static final int MoreData = 0x7f;
- public static final int ConstructedBit = 0x20;
- public static final int ClassShift = 6;
- public static final int ClassMask = 0x3;
- public static final int MoreWidth = 7;
- public static final int ByteWidth = 8;
- public static final int ByteMask = 0xff;
- public static final int ContinuationTag = 31;
-
- public static final int IndefiniteLength = -1;
-
- private static final Map<Integer, Asn1Tag> sTagMap = new HashMap<>();
-
- static {
- sTagMap.put(TAG_UNIVZERO, Asn1Tag.UNIVZERO);
- sTagMap.put(TAG_BOOLEAN, Asn1Tag.BOOLEAN);
- sTagMap.put(TAG_INTEGER, Asn1Tag.INTEGER);
- sTagMap.put(TAG_BITSTRING, Asn1Tag.BITSTRING);
- sTagMap.put(TAG_OCTET_STRING, Asn1Tag.OCTET_STRING);
- sTagMap.put(TAG_NULL, Asn1Tag.NULL);
- sTagMap.put(TAG_OID, Asn1Tag.OID);
- sTagMap.put(TAG_ObjectDescriptor, Asn1Tag.ObjectDescriptor);
- sTagMap.put(TAG_EXTERNAL, Asn1Tag.EXTERNAL);
- sTagMap.put(TAG_REAL, Asn1Tag.REAL);
- sTagMap.put(TAG_ENUMERATED, Asn1Tag.ENUMERATED);
- sTagMap.put(TAG_UTF8String, Asn1Tag.UTF8String);
- sTagMap.put(TAG_RelativeOID, Asn1Tag.RelativeOID);
- sTagMap.put(TAG_SEQ, Asn1Tag.SEQUENCE);
- sTagMap.put(TAG_SET, Asn1Tag.SET);
- sTagMap.put(TAG_NumericString, Asn1Tag.NumericString);
- sTagMap.put(TAG_PrintableString, Asn1Tag.PrintableString);
- sTagMap.put(TAG_T61String, Asn1Tag.T61String);
- sTagMap.put(TAG_VideotexString, Asn1Tag.VideotexString);
- sTagMap.put(TAG_IA5String, Asn1Tag.IA5String);
- sTagMap.put(TAG_UTCTime, Asn1Tag.UTCTime);
- sTagMap.put(TAG_GeneralizedTime, Asn1Tag.GeneralizedTime);
- sTagMap.put(TAG_GraphicString, Asn1Tag.GraphicString);
- sTagMap.put(TAG_VisibleString, Asn1Tag.VisibleString);
- sTagMap.put(TAG_GeneralString, Asn1Tag.GeneralString);
- sTagMap.put(TAG_UniversalString, Asn1Tag.UniversalString);
- sTagMap.put(TAG_BMPString, Asn1Tag.BMPString);
- }
-
- public static Asn1Tag mapTag(int tag) {
- return sTagMap.get(tag);
- }
-
- public static Collection<Asn1Object> decode(ByteBuffer data) throws DecodeException {
- Asn1Constructed root =
- new Asn1Constructed(0, null, data.remaining(), data, data.position());
- decode(0, root);
- return root.getChildren();
- }
-
- private static void decode(int level, Asn1Constructed parent) throws DecodeException {
- ByteBuffer data = parent.getPayload();
- while (data.hasRemaining()) {
- int tagPosition = data.position();
- int propMask = data.get(tagPosition) & ByteMask;
- if (propMask == 0 && parent.isIndefiniteLength() && data.get(tagPosition + 1) == 0) {
- parent.setEndOfData(tagPosition);
- return;
- }
- Asn1Class asn1Class = Asn1Class.values()[(propMask >> ClassShift) & ClassMask];
- boolean constructed = (propMask & ConstructedBit) != 0;
-
- int tag = decodeTag(data);
- int length = decodeLength(data);
-
- if (constructed) {
- ByteBuffer payload = peelOff(data, length);
- Asn1Constructed root =
- new Asn1Constructed(tag, asn1Class, length, payload, tagPosition);
- decode(level + 1, root);
- if (length == IndefiniteLength) {
- data.position(root.getEndOfData() + 2); // advance past '00'
- }
- parent.addChild(root);
- } else {
- if (asn1Class != Asn1Class.Universal) {
- parent.addChild(new Asn1Octets(tag, asn1Class, length, data));
- } else {
- parent.addChild(buildScalar(tag, asn1Class, length, data));
- }
- }
- }
- }
-
- private static ByteBuffer peelOff(ByteBuffer base, int length) {
- ByteBuffer copy = base.duplicate();
- if (length == IndefiniteLength) {
- return copy;
- }
- copy.limit(copy.position() + length);
- base.position(base.position() + length);
- return copy;
- }
-
- private static Asn1Object buildScalar(int tag, Asn1Class asn1Class, int length, ByteBuffer data)
- throws DecodeException {
- switch (tag) {
- case TAG_BOOLEAN:
- return new Asn1Boolean(tag, asn1Class, length, data);
- case TAG_INTEGER:
- case TAG_ENUMERATED:
- return new Asn1Integer(tag, asn1Class, length, data);
- case TAG_BITSTRING:
- int bitResidual = data.get() & ByteMask;
- return new Asn1Octets(tag, asn1Class, length, data, bitResidual);
- case TAG_OCTET_STRING:
- return new Asn1Octets(tag, asn1Class, length, data);
- case TAG_OID:
- return new Asn1Oid(tag, asn1Class, length, data);
- case TAG_UTF8String:
- case TAG_NumericString:
- case TAG_PrintableString:
- case TAG_T61String:
- case TAG_VideotexString:
- case TAG_IA5String:
- case TAG_GraphicString:
- case TAG_VisibleString:
- case TAG_GeneralString:
- case TAG_UniversalString:
- case TAG_BMPString:
- return new Asn1String(tag, asn1Class, length, data);
- case TAG_GeneralizedTime:
- case TAG_UTCTime:
- // Should really be a dedicated time object
- return new Asn1String(tag, asn1Class, length, data);
- default:
- return new Asn1Octets(tag, asn1Class, length, data);
- }
- }
-
- private static int decodeTag(ByteBuffer data) throws DecodeException {
- int tag;
- byte tag0 = data.get();
-
- if ((tag = (tag0 & ContinuationTag)) == ContinuationTag) {
- int tagByte;
- tag = 0;
- while (((tagByte = data.get() & ByteMask) & MoreBit) != 0) {
- tag = (tag << MoreWidth) | (tagByte & MoreData);
- if ((tag & IntOverflow) != 0)
- throw new DecodeException("Tag overflow", data.position());
- }
- tag = (tag << MoreWidth) | tagByte;
- }
- return tag;
- }
-
- private static int decodeLength(ByteBuffer data) throws DecodeException {
- int length;
- int lenlen = data.get() & ByteMask;
-
- if ((lenlen & MoreBit) == 0) // One byte encoding
- length = lenlen;
- else {
- lenlen &= MoreData;
- if (lenlen == 0) {
- return IndefiniteLength;
- }
- length = 0;
- while (lenlen-- > 0) {
- length = (length << ByteWidth) | (data.get() & ByteMask);
- if ((length & IntOverflow) != 0 && lenlen > 0)
- throw new DecodeException("Length overflow", data.position());
- }
- }
- return length;
- }
-
-}
diff --git a/packages/Osu/src/com/android/hotspot2/asn1/Asn1ID.java b/packages/Osu/src/com/android/hotspot2/asn1/Asn1ID.java
deleted file mode 100644
index 452d85ca30fd..000000000000
--- a/packages/Osu/src/com/android/hotspot2/asn1/Asn1ID.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.android.hotspot2.asn1;
-
-public class Asn1ID {
- private final int mTag;
- private final Asn1Class mClass;
-
- public Asn1ID(int tag, Asn1Class asn1Class) {
- mTag = tag;
- mClass = asn1Class;
- }
-
- public int getTag() {
- return mTag;
- }
-
- public Asn1Class getAsn1Class() {
- return mClass;
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/asn1/Asn1Integer.java b/packages/Osu/src/com/android/hotspot2/asn1/Asn1Integer.java
deleted file mode 100644
index 5180a4d5819a..000000000000
--- a/packages/Osu/src/com/android/hotspot2/asn1/Asn1Integer.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.android.hotspot2.asn1;
-
-import java.math.BigInteger;
-import java.nio.ByteBuffer;
-import java.util.Collection;
-
-public class Asn1Integer extends Asn1Object {
- private static final int SignBit = 0x80;
-
- private final long mValue;
- private final BigInteger mBigValue;
-
- public Asn1Integer(int tag, Asn1Class asn1Class, int length, ByteBuffer data) {
- super(tag, asn1Class, false, length);
-
- if (length <= 8) {
- long value = (data.get(data.position()) & SignBit) != 0 ? -1 : 0;
- for (int n = 0; n < length; n++) {
- value = (value << Byte.SIZE) | data.get();
- }
- mValue = value;
- mBigValue = null;
- } else {
- byte[] payload = new byte[length];
- data.get(payload);
- mValue = 0;
- mBigValue = new BigInteger(payload);
- }
- }
-
- public boolean isBigValue() {
- return mBigValue != null;
- }
-
- public long getValue() {
- return mValue;
- }
-
- public BigInteger getBigValue() {
- return mBigValue;
- }
-
- @Override
- public Collection<Asn1Object> getChildren() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String toString() {
- if (isBigValue()) {
- return super.toString() + '=' + mBigValue.toString(16);
- } else {
- return super.toString() + '=' + mValue;
- }
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/asn1/Asn1Object.java b/packages/Osu/src/com/android/hotspot2/asn1/Asn1Object.java
deleted file mode 100644
index 813758367cb9..000000000000
--- a/packages/Osu/src/com/android/hotspot2/asn1/Asn1Object.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package com.android.hotspot2.asn1;
-
-import java.nio.ByteBuffer;
-import java.util.Collection;
-
-public abstract class Asn1Object {
- private final int mTag;
- private final Asn1Class mClass;
- private final boolean mConstructed;
- private final int mLength;
- private final ByteBuffer mPayload;
-
- protected Asn1Object(int tag, Asn1Class asn1Class, boolean constructed, int length) {
- this(tag, asn1Class, constructed, length, null);
- }
-
- protected Asn1Object(int tag, Asn1Class asn1Class, boolean constructed,
- int length, ByteBuffer payload) {
- mTag = tag;
- mClass = asn1Class;
- mConstructed = constructed;
- mLength = length;
- mPayload = payload != null ? payload.duplicate() : null;
- }
-
- public int getTag() {
- return mTag;
- }
-
- public Asn1Class getAsn1Class() {
- return mClass;
- }
-
- public boolean isConstructed() {
- return mConstructed;
- }
-
- public boolean isIndefiniteLength() {
- return mLength == Asn1Decoder.IndefiniteLength;
- }
-
- public int getLength() {
- return mLength;
- }
-
- public ByteBuffer getPayload() {
- return mPayload != null ? mPayload.duplicate() : null;
- }
-
- protected ByteBuffer getPayload(int position) {
- if (mPayload == null) {
- return null;
- }
- ByteBuffer encoding = mPayload.duplicate();
- encoding.position(position);
- return encoding;
- }
-
- protected void setEndOfData(int position) {
- mPayload.limit(position);
- }
-
- protected int getEndOfData() {
- return mPayload.limit();
- }
-
- public boolean matches(Asn1ID id) {
- return mTag == id.getTag() && mClass == id.getAsn1Class();
- }
-
- public String toSimpleString() {
- Asn1Tag tag = mClass == Asn1Class.Universal ? Asn1Decoder.mapTag(mTag) : null;
- if (tag != null) {
- return tag.name();
- } else if (mClass == Asn1Class.Universal) {
- return String.format("[%d]", mTag);
- } else {
- return String.format("[%s %d]", mClass, mTag);
- }
- }
-
- public abstract Collection<Asn1Object> getChildren();
-
- @Override
- public String toString() {
- return toSimpleString();
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/asn1/Asn1Octets.java b/packages/Osu/src/com/android/hotspot2/asn1/Asn1Octets.java
deleted file mode 100644
index 1e1995315a8f..000000000000
--- a/packages/Osu/src/com/android/hotspot2/asn1/Asn1Octets.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.android.hotspot2.asn1;
-
-import java.nio.ByteBuffer;
-import java.util.Collection;
-
-public class Asn1Octets extends Asn1Object {
- private final byte[] mOctets;
- private final int mBitResidual;
-
- public Asn1Octets(int tag, Asn1Class asn1Class, int length, ByteBuffer data) {
- super(tag, asn1Class, false, length);
- mOctets = new byte[length];
- data.get(mOctets);
- mBitResidual = -1;
- }
-
- public Asn1Octets(int tag, Asn1Class asn1Class, int length, ByteBuffer data, int bitResidual) {
- super(tag, asn1Class, false, length);
- mOctets = new byte[length - 1];
- data.get(mOctets);
- mBitResidual = bitResidual;
- }
-
- public byte[] getOctets() {
- return mOctets;
- }
-
- @Override
- public Collection<Asn1Object> getChildren() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- for (byte b : mOctets) {
- sb.append(String.format(" %02x", b & Asn1Decoder.ByteMask));
- }
- if (mBitResidual >= 0) {
- return super.toString() + '=' + sb + '/' + mBitResidual;
- } else if (getTag() == Asn1Decoder.TAG_NULL && getLength() == 0) {
- return super.toString();
- } else {
- return super.toString() + '=' + sb;
- }
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/asn1/Asn1Oid.java b/packages/Osu/src/com/android/hotspot2/asn1/Asn1Oid.java
deleted file mode 100644
index 50f055368979..000000000000
--- a/packages/Osu/src/com/android/hotspot2/asn1/Asn1Oid.java
+++ /dev/null
@@ -1,212 +0,0 @@
-package com.android.hotspot2.asn1;
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class Asn1Oid extends Asn1Object {
- public static final int OidMaxOctet1 = 2;
- public static final int OidOctet1Modulus = 40;
-
- private final List<Long> mArcs;
- private final int mHashcode;
-
- private static final Map<Asn1Oid, String> sOidMap = new HashMap<>();
-
- public Asn1Oid(int tag, Asn1Class asn1Class, int length, ByteBuffer data)
- throws DecodeException {
- super(tag, asn1Class, false, length);
-
- if (length == 0)
- throw new DecodeException("oid-encoding length is zero", data.position());
-
- mArcs = new ArrayList<>();
-
- ByteBuffer payload = data.duplicate();
- payload.limit(payload.position() + length);
- data.position(data.position() + length);
-
- byte current = payload.get();
- long seg01 = current & Asn1Decoder.ByteMask;
- long segValue = seg01 / OidOctet1Modulus;
- int hashcode = (int) segValue;
- mArcs.add(segValue);
- segValue = seg01 - segValue * OidOctet1Modulus;
- hashcode = hashcode * 31 + (int) segValue;
- mArcs.add(segValue);
-
- current = 0;
- segValue = 0L;
-
- while (payload.hasRemaining()) {
- current = payload.get();
- segValue |= current & Asn1Decoder.MoreData;
- if ((current & Asn1Decoder.MoreBit) == 0) {
- hashcode = hashcode * 31 + (int) segValue;
- mArcs.add(segValue);
- segValue = 0L;
- } else
- segValue <<= Asn1Decoder.MoreWidth;
- }
- if ((current & Asn1Decoder.MoreBit) != 0)
- throw new DecodeException("Illegal (end of) oid-encoding", payload.position());
- mHashcode = hashcode;
- }
-
- public Asn1Oid(Long... arcs) {
- super(Asn1Decoder.TAG_OID, Asn1Class.Universal, false, -1);
- mArcs = Arrays.asList(arcs);
- int hashcode = 0;
- for (long arc : arcs) {
- hashcode = hashcode * 31 + (int) arc;
- }
- mHashcode = hashcode;
- }
-
- @Override
- public int hashCode() {
- return mHashcode;
- }
-
- @Override
- public boolean equals(Object thatObject) {
- return !(thatObject == null || thatObject.getClass() != Asn1Oid.class) &&
- mArcs.equals(((Asn1Oid) thatObject).mArcs);
- }
-
- public String toOIDString() {
- StringBuilder sb = new StringBuilder();
- boolean first = true;
- for (long arc : mArcs) {
- if (first) {
- first = false;
- } else {
- sb.append('.');
- }
- sb.append(arc);
- }
- return sb.toString();
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append(toOIDString());
- String name = sOidMap.get(this);
- if (name != null) {
- sb.append(" (").append(name).append(')');
- }
- return super.toString() + '=' + sb.toString();
- }
-
- @Override
- public Collection<Asn1Object> getChildren() {
- throw new UnsupportedOperationException();
- }
-
- public static final Asn1Oid PKCS7Data = new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 7L, 1L);
- public static final Asn1Oid PKCS7SignedData = new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 7L, 2L);
- // encoded as an IA5STRING type
- public static final Asn1Oid OidMacAddress = new Asn1Oid(1L, 3L, 6L, 1L, 1L, 1L, 1L, 22L);
- // encoded as an IA5STRING type
- public static final Asn1Oid OidImei = new Asn1Oid(1L, 3L, 6L, 1L, 4L, 1L, 40808L, 1L, 1L, 3L);
- // encoded as a BITSTRING type
- public static final Asn1Oid OidMeid = new Asn1Oid(1L, 3L, 6L, 1L, 4L, 1L, 40808L, 1L, 1L, 4L);
- // encoded as a PRINTABLESTRING type
- public static final Asn1Oid OidDevId = new Asn1Oid(1L, 3L, 6L, 1L, 4L, 1L, 40808L, 1L, 1L, 5L);
-
- //sOidMap.put(new Asn1Oid(1L, 2L, 840L, 10040L, 4L, 1L), "algo_id_dsa");
- //sOidMap.put(new Asn1Oid(1L, 2L, 840L, 10040L, 4L, 3L), "algo_id_dsawithsha1");
- //sOidMap.put(new Asn1Oid(1L, 2L, 840L, 10045L, 2L, 1L), "algo_id_ecPublicKey");
- //sOidMap.put(new Asn1Oid(1L, 2L, 840L, 10045L, 4L, 3L, 3L), "eccdaWithSHA384");
- //sOidMap.put(new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 1L, 1L), "algo_id_rsaEncryption");
- //sOidMap.put(new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 1L, 2L), "algo_id_md2WithRSAEncryption");
- //sOidMap.put(new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 1L, 4L), "algo_id_md5WithRSAEncryption");
- //sOidMap.put(new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 1L, 5L), "algo_id_sha1WithRSAEncryption");
- //sOidMap.put(new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 1L, 11L),
- // "algo_id_sha256WithRSAEncryption");
-
- static {
- sOidMap.put(new Asn1Oid(0L, 0L), "NullOid");
- sOidMap.put(new Asn1Oid(0L, 9L, 2342L, 19200300L, 100L, 1L, 25L), "domComp");
-
- sOidMap.put(OidMacAddress, "mac-address");
- sOidMap.put(new Asn1Oid(1L, 2L, 840L, 10040L, 4L, 1L), "algo_id_dsa");
- sOidMap.put(new Asn1Oid(1L, 2L, 840L, 10040L, 4L, 3L), "algo_id_dsawithsha1");
- sOidMap.put(new Asn1Oid(1L, 2L, 840L, 10045L, 2L, 1L), "algo_id_ecPublicKey");
- sOidMap.put(new Asn1Oid(1L, 2L, 840L, 10045L, 4L, 3L, 3L), "eccdaWithSHA384");
- sOidMap.put(new Asn1Oid(1L, 2L, 840L, 10046L, 2L, 1L), "algo_id_dhpublicnumber");
- sOidMap.put(new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 1L, 1L), "algo_id_rsaEncryption");
- sOidMap.put(new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 1L, 2L), "algo_id_md2WithRSAEncryption");
- sOidMap.put(new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 1L, 4L), "algo_id_md5WithRSAEncryption");
- sOidMap.put(new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 1L, 5L),
- "algo_id_sha1WithRSAEncryption");
- sOidMap.put(new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 1L, 11L),
- "algo_id_sha256WithRSAEncryption");
- sOidMap.put(new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 7L), "pkcs7");
- sOidMap.put(PKCS7Data, "pkcs7-data");
- sOidMap.put(PKCS7SignedData, "pkcs7-signedData");
- sOidMap.put(new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 9L, 1L), "emailAddress");
- sOidMap.put(new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 9L, 7L), "challengePassword");
- sOidMap.put(new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 9L, 14L), "extensionRequest");
- sOidMap.put(new Asn1Oid(1L, 2L, 840L, 113549L, 3L, 2L), "algo_id_RC2_CBC");
- sOidMap.put(new Asn1Oid(1L, 2L, 840L, 113549L, 3L, 4L), "algo_id_RC4_ENC");
- sOidMap.put(new Asn1Oid(1L, 2L, 840L, 113549L, 3L, 7L), "algo_id_DES_EDE3_CBC");
- sOidMap.put(new Asn1Oid(1L, 2L, 840L, 113549L, 3L, 9L), "algo_id_RC5_CBC_PAD");
- sOidMap.put(new Asn1Oid(1L, 2L, 840L, 113549L, 3L, 10L), "algo_id_desCDMF");
- sOidMap.put(new Asn1Oid(1L, 3L, 6L, 1L, 4L, 1L, 40808L, 1L, 1L, 2L), "id-kp-HS2.0Auth");
- sOidMap.put(OidImei, "imei");
- sOidMap.put(OidMeid, "meid");
- sOidMap.put(OidDevId, "DevId");
- sOidMap.put(new Asn1Oid(1L, 3L, 6L, 1L, 5L, 5L, 7L, 1L, 1L),
- "certAuthorityInfoAccessSyntax");
- sOidMap.put(new Asn1Oid(1L, 3L, 6L, 1L, 5L, 5L, 7L, 1L, 11L),
- "certSubjectInfoAccessSyntax");
- sOidMap.put(new Asn1Oid(1L, 3L, 14L, 3L, 2L, 26L), "algo_id_SHA1");
- sOidMap.put(new Asn1Oid(1L, 3L, 132L, 0L, 34L), "secp384r1");
-
- sOidMap.put(new Asn1Oid(2L, 5L, 4L, 3L), "x500_CN");
- sOidMap.put(new Asn1Oid(2L, 5L, 4L, 4L), "x500_SN");
- sOidMap.put(new Asn1Oid(2L, 5L, 4L, 5L), "x500_serialNum");
- sOidMap.put(new Asn1Oid(2L, 5L, 4L, 6L), "x500_C");
- sOidMap.put(new Asn1Oid(2L, 5L, 4L, 7L), "x500_L");
- sOidMap.put(new Asn1Oid(2L, 5L, 4L, 8L), "x500_ST");
- sOidMap.put(new Asn1Oid(2L, 5L, 4L, 9L), "x500_STREET");
- sOidMap.put(new Asn1Oid(2L, 5L, 4L, 10L), "x500_O");
- sOidMap.put(new Asn1Oid(2L, 5L, 4L, 11L), "x500_OU");
- sOidMap.put(new Asn1Oid(2L, 5L, 4L, 12L), "x500_title");
- sOidMap.put(new Asn1Oid(2L, 5L, 4L, 13L), "x500_description");
- sOidMap.put(new Asn1Oid(2L, 5L, 4L, 17L), "x500_postalCode");
- sOidMap.put(new Asn1Oid(2L, 5L, 4L, 18L), "x500_poBox");
- sOidMap.put(new Asn1Oid(2L, 5L, 4L, 20L), "x500_phone");
- sOidMap.put(new Asn1Oid(2L, 5L, 4L, 41L), "x500_name");
- sOidMap.put(new Asn1Oid(2L, 5L, 4L, 42L), "x500_givenName");
- sOidMap.put(new Asn1Oid(2L, 5L, 4L, 44L), "x500_genQual");
- sOidMap.put(new Asn1Oid(2L, 5L, 4L, 43L), "x500_initials");
- sOidMap.put(new Asn1Oid(2L, 5L, 4L, 46L), "x500_dnQualifier");
- sOidMap.put(new Asn1Oid(2L, 5L, 4L, 65L), "x500_pseudonym");
- sOidMap.put(new Asn1Oid(2L, 5L, 29L, 9L), "certSubjectDirectoryAttributes");
- sOidMap.put(new Asn1Oid(2L, 5L, 29L, 14L), "certSubjectKeyIdentifier ");
- sOidMap.put(new Asn1Oid(2L, 5L, 29L, 15L), "certKeyUsage");
- sOidMap.put(new Asn1Oid(2L, 5L, 29L, 16L), "certPrivateKeyUsagePeriod");
- sOidMap.put(new Asn1Oid(2L, 5L, 29L, 17L), "certSubjectAltName");
- sOidMap.put(new Asn1Oid(2L, 5L, 29L, 18L), "certIssuerAltName");
- sOidMap.put(new Asn1Oid(2L, 5L, 29L, 19L), "certBasicConstraints");
- sOidMap.put(new Asn1Oid(2L, 5L, 29L, 30L), "certNameConstraints");
- sOidMap.put(new Asn1Oid(2L, 5L, 29L, 31L), "certCRLDistributionPoints");
- sOidMap.put(new Asn1Oid(2L, 5L, 29L, 32L), "certificatePolicies");
- sOidMap.put(new Asn1Oid(2L, 5L, 29L, 33L), "certPolicyMappings");
- sOidMap.put(new Asn1Oid(2L, 5L, 29L, 35L), "certAuthorityKeyIdentifier ");
- sOidMap.put(new Asn1Oid(2L, 5L, 29L, 36L), "certPolicyConstraints");
- sOidMap.put(new Asn1Oid(2L, 5L, 29L, 37L), "certExtKeyUsageSyntax");
- sOidMap.put(new Asn1Oid(2L, 5L, 29L, 46L), "certFreshestCRL");
- sOidMap.put(new Asn1Oid(2L, 5L, 29L, 54L), "certInhibitAnyPolicy");
- sOidMap.put(new Asn1Oid(2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 2L), "algo_id_aes128");
- sOidMap.put(new Asn1Oid(2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 22L), "algo_id_aes192");
- sOidMap.put(new Asn1Oid(2L, 16L, 840L, 1L, 101L, 3L, 4L, 1L, 42L), "algo_id_aes256");
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/asn1/Asn1String.java b/packages/Osu/src/com/android/hotspot2/asn1/Asn1String.java
deleted file mode 100644
index 37ed2b28c780..000000000000
--- a/packages/Osu/src/com/android/hotspot2/asn1/Asn1String.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.android.hotspot2.asn1;
-
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.Collection;
-
-public class Asn1String extends Asn1Object {
- private final String mString;
-
- public Asn1String(int tag, Asn1Class asn1Class, int length, ByteBuffer data) {
- super(tag, asn1Class, false, length);
-
- byte[] octets = new byte[length];
- data.get(octets);
- Charset charset = tag == Asn1Decoder.TAG_UTF8String
- ? StandardCharsets.UTF_8 : StandardCharsets.ISO_8859_1;
- mString = new String(octets, charset);
- }
-
- public String getString() {
- return mString;
- }
-
- @Override
- public Collection<Asn1Object> getChildren() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String toString() {
- return super.toString() + "='" + mString + '\'';
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/asn1/Asn1Tag.java b/packages/Osu/src/com/android/hotspot2/asn1/Asn1Tag.java
deleted file mode 100644
index 812948195c09..000000000000
--- a/packages/Osu/src/com/android/hotspot2/asn1/Asn1Tag.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.android.hotspot2.asn1;
-
-public enum Asn1Tag {
- UNIVZERO,
- BOOLEAN,
- INTEGER,
- BITSTRING,
- OCTET_STRING,
- NULL,
- OID,
- ObjectDescriptor,
- EXTERNAL,
- REAL,
- ENUMERATED,
- UTF8String,
- RelativeOID,
- SEQUENCE,
- SET,
- NumericString,
- PrintableString,
- T61String,
- VideotexString,
- IA5String,
- UTCTime,
- GeneralizedTime,
- GraphicString,
- VisibleString,
- GeneralString,
- UniversalString,
- BMPString
-}
diff --git a/packages/Osu/src/com/android/hotspot2/asn1/DecodeException.java b/packages/Osu/src/com/android/hotspot2/asn1/DecodeException.java
deleted file mode 100644
index 1f10ee4f6334..000000000000
--- a/packages/Osu/src/com/android/hotspot2/asn1/DecodeException.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.android.hotspot2.asn1;
-
-import java.io.IOException;
-
-public class DecodeException extends IOException {
- private final int mOffset;
-
- public DecodeException(String message, int offset) {
- super(message);
- mOffset = offset;
- }
-
- @Override
- public String toString() {
- return super.toString() + " at " + mOffset;
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/asn1/OidMappings.java b/packages/Osu/src/com/android/hotspot2/asn1/OidMappings.java
deleted file mode 100644
index 01a6fd696e56..000000000000
--- a/packages/Osu/src/com/android/hotspot2/asn1/OidMappings.java
+++ /dev/null
@@ -1,197 +0,0 @@
-package com.android.hotspot2.asn1;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-public class OidMappings {
- public static class SigEntry {
- private final String mSigAlgo;
- private final Asn1Oid mKeyAlgo;
-
- private SigEntry(String sigAlgo, Asn1Oid keyAlgo) {
- mSigAlgo = sigAlgo;
- mKeyAlgo = keyAlgo;
- }
-
- public String getSigAlgo() {
- return mSigAlgo;
- }
-
- public Asn1Oid getKeyAlgo() {
- return mKeyAlgo;
- }
- }
-
- public static final String IdPeLogotype = "1.3.6.1.5.5.7.1.12";
- public static final String IdCeSubjectAltName = "2.5.29.17";
-
- private static final Map<Asn1Oid, String> sCryptoMapping = new HashMap<>();
- private static final Map<Asn1Oid, String> sNameMapping = new HashMap<>();
- private static final Set<Asn1Oid> sIDMapping = new HashSet<>();
- private static final Map<Asn1Oid, SigEntry> sSigAlgos = new HashMap<>();
-
- // DSA
- private static final Asn1Oid sAlgo_DSA = new Asn1Oid(1L, 2L, 840L, 10040L, 4L, 1L);
- private static final Asn1Oid sAlgo_SHA1withDSA = new Asn1Oid(1L, 2L, 840L, 10040L, 4L, 3L);
-
- // RSA
- public static final Asn1Oid sAlgo_RSA = new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 1L, 1L);
- private static final Asn1Oid sAlgo_MD2withRSA = new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 1L, 2L);
- private static final Asn1Oid sAlgo_MD5withRSA = new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 1L, 4L);
- private static final Asn1Oid sAlgo_SHA1withRSA = new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 1L, 5L);
- private static final Asn1Oid sAlgo_SHA224withRSA =
- new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 1L, 14L); // n/a
- private static final Asn1Oid sAlgo_SHA256withRSA =
- new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 1L, 11L);
- private static final Asn1Oid sAlgo_SHA384withRSA =
- new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 1L, 12L);
- private static final Asn1Oid sAlgo_SHA512withRSA =
- new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 1L, 13L);
-
- // ECC
- public static final Asn1Oid sAlgo_EC = new Asn1Oid(1L, 2L, 840L, 10045L, 2L, 1L);
- private static final Asn1Oid sAlgo_SHA1withECDSA = new Asn1Oid(1L, 2L, 840L, 10045L, 4L, 1L);
- private static final Asn1Oid sAlgo_SHA224withECDSA =
- new Asn1Oid(1L, 2L, 840L, 10045L, 4L, 3L, 1L); // n/a
- private static final Asn1Oid sAlgo_SHA256withECDSA =
- new Asn1Oid(1L, 2L, 840L, 10045L, 4L, 3L, 2L);
- private static final Asn1Oid sAlgo_SHA384withECDSA =
- new Asn1Oid(1L, 2L, 840L, 10045L, 4L, 3L, 3L);
- private static final Asn1Oid sAlgo_SHA512withECDSA =
- new Asn1Oid(1L, 2L, 840L, 10045L, 4L, 3L, 4L);
-
- private static final Asn1Oid sAlgo_MD2 = new Asn1Oid(1L, 2L, 840L, 113549L, 2L, 2L);
- private static final Asn1Oid sAlgo_MD5 = new Asn1Oid(1L, 2L, 840L, 113549L, 2L, 5L);
- private static final Asn1Oid sAlgo_SHA1 = new Asn1Oid(1L, 3L, 14L, 3L, 2L, 26L);
- private static final Asn1Oid sAlgo_SHA256 =
- new Asn1Oid(2L, 16L, 840L, 1L, 101L, 3L, 4L, 2L, 1L);
- private static final Asn1Oid sAlgo_SHA384 =
- new Asn1Oid(2L, 16L, 840L, 1L, 101L, 3L, 4L, 2L, 2L);
- private static final Asn1Oid sAlgo_SHA512 =
- new Asn1Oid(2L, 16L, 840L, 1L, 101L, 3L, 4L, 2L, 3L);
-
- // HS2.0 stuff:
- public static final Asn1Oid sPkcs9AtChallengePassword =
- new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 9L, 7L);
- public static final Asn1Oid sExtensionRequest = new Asn1Oid(1L, 2L, 840L, 113549L, 1L, 9L, 14L);
-
- public static final Asn1Oid sMAC = new Asn1Oid(1L, 3L, 6L, 1L, 1L, 1L, 1L, 22L);
- public static final Asn1Oid sIMEI = new Asn1Oid(1L, 3L, 6L, 1L, 4L, 1L, 40808L, 1L, 1L, 3L);
- public static final Asn1Oid sMEID = new Asn1Oid(1L, 3L, 6L, 1L, 4L, 1L, 40808L, 1L, 1L, 4L);
- public static final Asn1Oid sDevID = new Asn1Oid(1L, 3L, 6L, 1L, 4L, 1L, 40808L, 1L, 1L, 5L);
-
- public static final Asn1Oid sIdWfaHotspotFriendlyName =
- new Asn1Oid(1L, 3L, 6L, 1L, 4L, 1L, 40808L, 1L, 1L, 1L);
-
- static {
- sCryptoMapping.put(sAlgo_DSA, "DSA");
- sCryptoMapping.put(sAlgo_RSA, "RSA");
- sCryptoMapping.put(sAlgo_EC, "EC");
-
- sSigAlgos.put(sAlgo_SHA1withDSA, new SigEntry("SHA1withDSA", sAlgo_DSA));
-
- sSigAlgos.put(sAlgo_MD2withRSA, new SigEntry("MD2withRSA", sAlgo_RSA));
- sSigAlgos.put(sAlgo_MD5withRSA, new SigEntry("MD5withRSA", sAlgo_RSA));
- sSigAlgos.put(sAlgo_SHA1withRSA, new SigEntry("SHA1withRSA", sAlgo_RSA));
- sSigAlgos.put(sAlgo_SHA224withRSA, new SigEntry(null, sAlgo_RSA));
- sSigAlgos.put(sAlgo_SHA256withRSA, new SigEntry("SHA256withRSA", sAlgo_RSA));
- sSigAlgos.put(sAlgo_SHA384withRSA, new SigEntry("SHA384withRSA", sAlgo_RSA));
- sSigAlgos.put(sAlgo_SHA512withRSA, new SigEntry("SHA512withRSA", sAlgo_RSA));
-
- sSigAlgos.put(sAlgo_SHA1withECDSA, new SigEntry("SHA1withECDSA", sAlgo_EC));
- sSigAlgos.put(sAlgo_SHA224withECDSA, new SigEntry(null, sAlgo_EC));
- sSigAlgos.put(sAlgo_SHA256withECDSA, new SigEntry("SHA256withECDSA", sAlgo_EC));
- sSigAlgos.put(sAlgo_SHA384withECDSA, new SigEntry("SHA384withECDSA", sAlgo_EC));
- sSigAlgos.put(sAlgo_SHA512withECDSA, new SigEntry("SHA512withECDSA", sAlgo_EC));
-
- sIDMapping.add(sMAC);
- sIDMapping.add(sIMEI);
- sIDMapping.add(sMEID);
- sIDMapping.add(sDevID);
-
- for (Map.Entry<Asn1Oid, String> entry : sCryptoMapping.entrySet()) {
- sNameMapping.put(entry.getKey(), entry.getValue());
- }
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 1L), "sect163k1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 2L), "sect163r1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 3L), "sect239k1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 4L), "sect113r1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 5L), "sect113r2");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 6L), "secp112r1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 7L), "secp112r2");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 8L), "secp160r1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 9L), "secp160k1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 10L), "secp256k1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 15L), "sect163r2");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 16L), "sect283k1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 17L), "sect283r1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 22L), "sect131r1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 23L), "sect131r2");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 24L), "sect193r1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 25L), "sect193r2");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 26L), "sect233k1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 27L), "sect233r1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 28L), "secp128r1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 29L), "secp128r2");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 30L), "secp160r2");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 31L), "secp192k1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 32L), "secp224k1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 33L), "secp224r1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 34L), "secp384r1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 35L), "secp521r1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 36L), "sect409k1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 37L), "sect409r1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 38L), "sect571k1");
- sNameMapping.put(new Asn1Oid(1L, 3L, 132L, 0L, 39L), "sect571r1");
- sNameMapping.put(new Asn1Oid(1L, 2L, 840L, 10045L, 3L, 1L, 1L), "secp192r1");
- sNameMapping.put(new Asn1Oid(1L, 2L, 840L, 10045L, 3L, 1L, 7L), "secp256r1");
- sNameMapping.put(new Asn1Oid(1L, 2L, 840L, 10045L, 3L, 1L, 2L), "prime192v2"); // X9.62
- sNameMapping.put(new Asn1Oid(1L, 2L, 840L, 10045L, 3L, 1L, 3L), "prime192v3"); // X9.62
- sNameMapping.put(new Asn1Oid(1L, 2L, 840L, 10045L, 3L, 1L, 4L), "prime239v1"); // X9.62
- sNameMapping.put(new Asn1Oid(1L, 2L, 840L, 10045L, 3L, 1L, 5L), "prime239v2"); // X9.62
- sNameMapping.put(new Asn1Oid(1L, 2L, 840L, 10045L, 3L, 1L, 6L), "prime239v3"); // X9.62
- sNameMapping.put(new Asn1Oid(1L, 2L, 840L, 10045L, 3L, 0L, 5L), "c2tnb191v1"); // X9.62
- sNameMapping.put(new Asn1Oid(1L, 2L, 840L, 10045L, 3L, 0L, 6L), "c2tnb191v2"); // X9.62
- sNameMapping.put(new Asn1Oid(1L, 2L, 840L, 10045L, 3L, 0L, 7L), "c2tnb191v3"); // X9.62
- sNameMapping.put(new Asn1Oid(1L, 2L, 840L, 10045L, 3L, 0L, 11L), "c2tnb239v1"); // X9.62
- sNameMapping.put(new Asn1Oid(1L, 2L, 840L, 10045L, 3L, 0L, 12L), "c2tnb239v2"); // X9.62
- sNameMapping.put(new Asn1Oid(1L, 2L, 840L, 10045L, 3L, 0L, 13L), "c2tnb239v3"); // X9.62
- sNameMapping.put(new Asn1Oid(1L, 2L, 840L, 10045L, 3L, 0L, 18L), "c2tnb359v1"); // X9.62
- sNameMapping.put(new Asn1Oid(1L, 2L, 840L, 10045L, 3L, 0L, 20L), "c2tnb431r1"); // X9.62
-
- sNameMapping.put(sAlgo_MD2, "MD2");
- sNameMapping.put(sAlgo_MD5, "MD5");
- sNameMapping.put(sAlgo_SHA1, "SHA-1");
- sNameMapping.put(sAlgo_SHA256, "SHA-256");
- sNameMapping.put(sAlgo_SHA384, "SHA-384");
- sNameMapping.put(sAlgo_SHA512, "SHA-512");
- }
-
- public static SigEntry getSigEntry(Asn1Oid oid) {
- return sSigAlgos.get(oid);
- }
-
- public static String getCryptoID(Asn1Oid oid) {
- return sCryptoMapping.get(oid);
- }
-
- public static String getJCEName(Asn1Oid oid) {
- return sNameMapping.get(oid);
- }
-
- public static String getSigAlgoName(Asn1Oid oid) {
- SigEntry sigEntry = sSigAlgos.get(oid);
- return sigEntry != null ? sigEntry.getSigAlgo() : null;
- }
-
- public static String getKeyAlgoName(Asn1Oid oid) {
- SigEntry sigEntry = sSigAlgos.get(oid);
- return sigEntry != null ? sNameMapping.get(sigEntry.getKeyAlgo()) : null;
- }
-
- public static boolean isIDAttribute(Asn1Oid oid) {
- return sIDMapping.contains(oid);
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/est/ESTHandler.java b/packages/Osu/src/com/android/hotspot2/est/ESTHandler.java
deleted file mode 100644
index cdcff8017497..000000000000
--- a/packages/Osu/src/com/android/hotspot2/est/ESTHandler.java
+++ /dev/null
@@ -1,501 +0,0 @@
-package com.android.hotspot2.est;
-
-import android.net.Network;
-import android.util.Base64;
-import android.util.Log;
-
-import com.android.hotspot2.OMADMAdapter;
-import com.android.hotspot2.asn1.Asn1Class;
-import com.android.hotspot2.asn1.Asn1Constructed;
-import com.android.hotspot2.asn1.Asn1Decoder;
-import com.android.hotspot2.asn1.Asn1ID;
-import com.android.hotspot2.asn1.Asn1Integer;
-import com.android.hotspot2.asn1.Asn1Object;
-import com.android.hotspot2.asn1.Asn1Oid;
-import com.android.hotspot2.asn1.OidMappings;
-import com.android.hotspot2.osu.HTTPHandler;
-import com.android.hotspot2.osu.OSUFlowManager;
-import com.android.hotspot2.osu.OSUSocketFactory;
-import com.android.hotspot2.osu.commands.GetCertData;
-import com.android.hotspot2.pps.HomeSP;
-import com.android.hotspot2.utils.HTTPMessage;
-import com.android.hotspot2.utils.HTTPResponse;
-import com.android.org.bouncycastle.asn1.ASN1Encodable;
-import com.android.org.bouncycastle.asn1.ASN1EncodableVector;
-import com.android.org.bouncycastle.asn1.ASN1Set;
-import com.android.org.bouncycastle.asn1.DERBitString;
-import com.android.org.bouncycastle.asn1.DEREncodableVector;
-import com.android.org.bouncycastle.asn1.DERIA5String;
-import com.android.org.bouncycastle.asn1.DERObjectIdentifier;
-import com.android.org.bouncycastle.asn1.DERPrintableString;
-import com.android.org.bouncycastle.asn1.DERSet;
-import com.android.org.bouncycastle.asn1.x509.Attribute;
-import com.android.org.bouncycastle.jce.PKCS10CertificationRequest;
-import com.android.org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.net.URL;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.security.AlgorithmParameters;
-import java.security.GeneralSecurityException;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.KeyStore;
-import java.security.PrivateKey;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.net.ssl.KeyManager;
-import javax.security.auth.x500.X500Principal;
-
-//import com.android.org.bouncycastle.jce.provider.BouncyCastleProvider;
-
-public class ESTHandler implements AutoCloseable {
- private static final String TAG = "HS2EST";
- private static final int MinRSAKeySize = 2048;
-
- private static final String CACERT_PATH = "/cacerts";
- private static final String CSR_PATH = "/csrattrs";
- private static final String SIMPLE_ENROLL_PATH = "/simpleenroll";
- private static final String SIMPLE_REENROLL_PATH = "/simplereenroll";
-
- private final URL mURL;
- private final String mUser;
- private final byte[] mPassword;
- private final OSUSocketFactory mSocketFactory;
- private final OMADMAdapter mOMADMAdapter;
-
- private final List<X509Certificate> mCACerts = new ArrayList<>();
- private final List<X509Certificate> mClientCerts = new ArrayList<>();
- private PrivateKey mClientKey;
-
- public ESTHandler(GetCertData certData, Network network, OMADMAdapter omadmAdapter,
- KeyManager km, KeyStore ks, HomeSP homeSP, OSUFlowManager.FlowType flowType)
- throws IOException, GeneralSecurityException {
- mURL = new URL(certData.getServer());
- mUser = certData.getUserName();
- mPassword = certData.getPassword();
- mSocketFactory = OSUSocketFactory.getSocketFactory(ks, homeSP, flowType,
- network, mURL, km, true);
- mOMADMAdapter = omadmAdapter;
- }
-
- @Override
- public void close() throws IOException {
- }
-
- public List<X509Certificate> getCACerts() {
- return mCACerts;
- }
-
- public List<X509Certificate> getClientCerts() {
- return mClientCerts;
- }
-
- public PrivateKey getClientKey() {
- return mClientKey;
- }
-
- private static String indent(int amount) {
- char[] indent = new char[amount * 2];
- Arrays.fill(indent, ' ');
- return new String(indent);
- }
-
- public void execute(boolean reenroll) throws IOException, GeneralSecurityException {
- URL caURL = new URL(mURL.getProtocol(), mURL.getHost(), mURL.getPort(),
- mURL.getFile() + CACERT_PATH);
-
- HTTPResponse response;
- try (HTTPHandler httpHandler = new HTTPHandler(StandardCharsets.ISO_8859_1, mSocketFactory,
- mUser, mPassword)) {
- response = httpHandler.doGetHTTP(caURL);
-
- if (!"application/pkcs7-mime".equals(response.getHeaders().
- get(HTTPMessage.ContentTypeHeader))) {
- throw new IOException("Unexpected Content-Type: " +
- response.getHeaders().get(HTTPMessage.ContentTypeHeader));
- }
- ByteBuffer octetBuffer = response.getBinaryPayload();
- Collection<Asn1Object> pkcs7Content1 = Asn1Decoder.decode(octetBuffer);
- for (Asn1Object asn1Object : pkcs7Content1) {
- Log.d(TAG, "---");
- Log.d(TAG, asn1Object.toString());
- }
- Log.d(TAG, CACERT_PATH);
-
- mCACerts.addAll(unpackPkcs7(octetBuffer));
- for (X509Certificate certificate : mCACerts) {
- Log.d(TAG, "CA-Cert: " + certificate.getSubjectX500Principal());
- }
-
- /*
- byte[] octets = new byte[octetBuffer.remaining()];
- octetBuffer.duplicate().get(octets);
- for (byte b : octets) {
- System.out.printf("%02x ", b & 0xff);
- }
- Log.d(TAG, );
- */
-
- /* + BC
- try {
- byte[] octets = new byte[octetBuffer.remaining()];
- octetBuffer.duplicate().get(octets);
- ASN1InputStream asnin = new ASN1InputStream(octets);
- for (int n = 0; n < 100; n++) {
- ASN1Primitive object = asnin.readObject();
- if (object == null) {
- break;
- }
- parseObject(object, 0);
- }
- }
- catch (Throwable t) {
- t.printStackTrace();
- }
-
- Collection<Asn1Object> pkcs7Content = Asn1Decoder.decode(octetBuffer);
- for (Asn1Object asn1Object : pkcs7Content) {
- Log.d(TAG, asn1Object);
- }
-
- if (pkcs7Content.size() != 1) {
- throw new IOException("Unexpected pkcs 7 container: " + pkcs7Content.size());
- }
-
- Asn1Constructed pkcs7Root = (Asn1Constructed) pkcs7Content.iterator().next();
- Iterator<Asn1ID> certPath = Arrays.asList(Pkcs7CertPath).iterator();
- Asn1Object certObject = pkcs7Root.findObject(certPath);
- if (certObject == null || certPath.hasNext()) {
- throw new IOException("Failed to find cert; returned object " + certObject +
- ", path " + (certPath.hasNext() ? "short" : "exhausted"));
- }
-
- ByteBuffer certOctets = certObject.getPayload();
- if (certOctets == null) {
- throw new IOException("No cert payload in: " + certObject);
- }
-
- byte[] certBytes = new byte[certOctets.remaining()];
- certOctets.get(certBytes);
-
- CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
- Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(certBytes));
- Log.d(TAG, "EST Cert: " + cert);
- */
-
- URL csrURL = new URL(mURL.getProtocol(), mURL.getHost(), mURL.getPort(),
- mURL.getFile() + CSR_PATH);
- response = httpHandler.doGetHTTP(csrURL);
-
- octetBuffer = response.getBinaryPayload();
- byte[] csrData = buildCSR(octetBuffer, mOMADMAdapter, httpHandler);
-
- /**/
- Collection<Asn1Object> o = Asn1Decoder.decode(ByteBuffer.wrap(csrData));
- Log.d(TAG, "CSR:");
- Log.d(TAG, o.iterator().next().toString());
- Log.d(TAG, "End CSR.");
- /**/
-
- URL enrollURL = new URL(mURL.getProtocol(), mURL.getHost(), mURL.getPort(),
- mURL.getFile() + (reenroll ? SIMPLE_REENROLL_PATH : SIMPLE_ENROLL_PATH));
- String data = Base64.encodeToString(csrData, Base64.DEFAULT);
- octetBuffer = httpHandler.exchangeBinary(enrollURL, data, "application/pkcs10");
-
- Collection<Asn1Object> pkcs7Content2 = Asn1Decoder.decode(octetBuffer);
- for (Asn1Object asn1Object : pkcs7Content2) {
- Log.d(TAG, "---");
- Log.d(TAG, asn1Object.toString());
- }
- mClientCerts.addAll(unpackPkcs7(octetBuffer));
- for (X509Certificate cert : mClientCerts) {
- Log.d(TAG, cert.toString());
- }
- }
- }
-
- private static final Asn1ID sSEQUENCE = new Asn1ID(Asn1Decoder.TAG_SEQ, Asn1Class.Universal);
- private static final Asn1ID sCTXT0 = new Asn1ID(0, Asn1Class.Context);
- private static final int PKCS7DataVersion = 1;
- private static final int PKCS7SignedDataVersion = 3;
-
- private static List<X509Certificate> unpackPkcs7(ByteBuffer pkcs7)
- throws IOException, GeneralSecurityException {
- Collection<Asn1Object> pkcs7Content = Asn1Decoder.decode(pkcs7);
-
- if (pkcs7Content.size() != 1) {
- throw new IOException("Unexpected pkcs 7 container: " + pkcs7Content.size());
- }
-
- Asn1Object data = pkcs7Content.iterator().next();
- if (!data.isConstructed() || !data.matches(sSEQUENCE)) {
- throw new IOException("Expected SEQ OF, got " + data.toSimpleString());
- } else if (data.getChildren().size() != 2) {
- throw new IOException("Expected content info to have two children, got " +
- data.getChildren().size());
- }
-
- Iterator<Asn1Object> children = data.getChildren().iterator();
- Asn1Object contentType = children.next();
- if (!contentType.equals(Asn1Oid.PKCS7SignedData)) {
- throw new IOException("Content not PKCS7 signed data");
- }
- Asn1Object content = children.next();
- if (!content.isConstructed() || !content.matches(sCTXT0)) {
- throw new IOException("Expected [CONTEXT 0] with one child, got " +
- content.toSimpleString() + ", " + content.getChildren().size());
- }
-
- Asn1Object signedData = content.getChildren().iterator().next();
- Map<Integer, Asn1Object> itemMap = new HashMap<>();
- for (Asn1Object item : signedData.getChildren()) {
- if (itemMap.put(item.getTag(), item) != null && item.getTag() != Asn1Decoder.TAG_SET) {
- throw new IOException("Duplicate item in SignedData: " + item.toSimpleString());
- }
- }
-
- Asn1Object versionObject = itemMap.get(Asn1Decoder.TAG_INTEGER);
- if (versionObject == null || !(versionObject instanceof Asn1Integer)) {
- throw new IOException("Bad or missing PKCS7 version: " + versionObject);
- }
- int pkcs7version = (int) ((Asn1Integer) versionObject).getValue();
- Asn1Object innerContentInfo = itemMap.get(Asn1Decoder.TAG_SEQ);
- if (innerContentInfo == null ||
- !innerContentInfo.isConstructed() ||
- !innerContentInfo.matches(sSEQUENCE) ||
- innerContentInfo.getChildren().size() != 1) {
- throw new IOException("Bad or missing PKCS7 contentInfo");
- }
- Asn1Object contentID = innerContentInfo.getChildren().iterator().next();
- if (pkcs7version == PKCS7DataVersion && !contentID.equals(Asn1Oid.PKCS7Data) ||
- pkcs7version == PKCS7SignedDataVersion && !contentID.equals(Asn1Oid.PKCS7SignedData)) {
- throw new IOException("Inner PKCS7 content (" + contentID +
- ") not expected for version " + pkcs7version);
- }
- Asn1Object certWrapper = itemMap.get(0);
- if (certWrapper == null || !certWrapper.isConstructed() || !certWrapper.matches(sCTXT0)) {
- throw new IOException("Expected [CONTEXT 0], got: " + certWrapper);
- }
-
- List<X509Certificate> certList = new ArrayList<>(certWrapper.getChildren().size());
- CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
- for (Asn1Object certObject : certWrapper.getChildren()) {
- ByteBuffer certOctets = ((Asn1Constructed) certObject).getEncoding();
- if (certOctets == null) {
- throw new IOException("No cert payload in: " + certObject);
- }
- byte[] certBytes = new byte[certOctets.remaining()];
- certOctets.get(certBytes);
-
- certList.add((X509Certificate) certFactory.
- generateCertificate(new ByteArrayInputStream(certBytes)));
- }
- return certList;
- }
-
- private byte[] buildCSR(ByteBuffer octetBuffer, OMADMAdapter omadmAdapter,
- HTTPHandler httpHandler) throws IOException, GeneralSecurityException {
-
- //Security.addProvider(new BouncyCastleProvider());
-
- Log.d(TAG, "/csrattrs:");
- /*
- byte[] octets = new byte[octetBuffer.remaining()];
- octetBuffer.duplicate().get(octets);
- for (byte b : octets) {
- System.out.printf("%02x ", b & 0xff);
- }
- */
- Collection<Asn1Object> csrs = Asn1Decoder.decode(octetBuffer);
- for (Asn1Object asn1Object : csrs) {
- Log.d(TAG, asn1Object.toString());
- }
-
- if (csrs.size() != 1) {
- throw new IOException("Unexpected object count in CSR attributes response: " +
- csrs.size());
- }
- Asn1Object sequence = csrs.iterator().next();
- if (sequence.getClass() != Asn1Constructed.class) {
- throw new IOException("Unexpected CSR attribute container: " + sequence);
- }
-
- String keyAlgo = null;
- Asn1Oid keyAlgoOID = null;
- String sigAlgo = null;
- String curveName = null;
- Asn1Oid pubCrypto = null;
- int keySize = -1;
- Map<Asn1Oid, ASN1Encodable> idAttributes = new HashMap<>();
-
- for (Asn1Object child : sequence.getChildren()) {
- if (child.getTag() == Asn1Decoder.TAG_OID) {
- Asn1Oid oid = (Asn1Oid) child;
- OidMappings.SigEntry sigEntry = OidMappings.getSigEntry(oid);
- if (sigEntry != null) {
- sigAlgo = sigEntry.getSigAlgo();
- keyAlgoOID = sigEntry.getKeyAlgo();
- keyAlgo = OidMappings.getJCEName(keyAlgoOID);
- } else if (oid.equals(OidMappings.sPkcs9AtChallengePassword)) {
- byte[] tlsUnique = httpHandler.getTLSUnique();
- if (tlsUnique != null) {
- idAttributes.put(oid, new DERPrintableString(
- Base64.encodeToString(tlsUnique, Base64.DEFAULT)));
- } else {
- Log.w(TAG, "Cannot retrieve TLS unique channel binding");
- }
- }
- } else if (child.getTag() == Asn1Decoder.TAG_SEQ) {
- Asn1Oid oid = null;
- Set<Asn1Oid> oidValues = new HashSet<>();
- List<Asn1Object> values = new ArrayList<>();
-
- for (Asn1Object attributeSeq : child.getChildren()) {
- if (attributeSeq.getTag() == Asn1Decoder.TAG_OID) {
- oid = (Asn1Oid) attributeSeq;
- } else if (attributeSeq.getTag() == Asn1Decoder.TAG_SET) {
- for (Asn1Object value : attributeSeq.getChildren()) {
- if (value.getTag() == Asn1Decoder.TAG_OID) {
- oidValues.add((Asn1Oid) value);
- } else {
- values.add(value);
- }
- }
- }
- }
- if (oid == null) {
- throw new IOException("Invalid attribute, no OID");
- }
- if (oid.equals(OidMappings.sExtensionRequest)) {
- for (Asn1Oid subOid : oidValues) {
- if (OidMappings.isIDAttribute(subOid)) {
- if (subOid.equals(OidMappings.sMAC)) {
- idAttributes.put(subOid, new DERIA5String(omadmAdapter.getMAC()));
- } else if (subOid.equals(OidMappings.sIMEI)) {
- idAttributes.put(subOid, new DERIA5String(omadmAdapter.getImei()));
- } else if (subOid.equals(OidMappings.sMEID)) {
- idAttributes.put(subOid, new DERBitString(omadmAdapter.getMeid()));
- } else if (subOid.equals(OidMappings.sDevID)) {
- idAttributes.put(subOid,
- new DERPrintableString(omadmAdapter.getDevID()));
- }
- }
- }
- } else if (OidMappings.getCryptoID(oid) != null) {
- pubCrypto = oid;
- if (!values.isEmpty()) {
- for (Asn1Object value : values) {
- if (value.getTag() == Asn1Decoder.TAG_INTEGER) {
- keySize = (int) ((Asn1Integer) value).getValue();
- }
- }
- }
- if (oid.equals(OidMappings.sAlgo_EC)) {
- if (oidValues.isEmpty()) {
- throw new IOException("No ECC curve name provided");
- }
- for (Asn1Oid value : oidValues) {
- curveName = OidMappings.getJCEName(value);
- if (curveName != null) {
- break;
- }
- }
- if (curveName == null) {
- throw new IOException("Found no ECC curve for " + oidValues);
- }
- }
- }
- }
- }
-
- if (keyAlgoOID == null) {
- throw new IOException("No public key algorithm specified");
- }
- if (pubCrypto != null && !pubCrypto.equals(keyAlgoOID)) {
- throw new IOException("Mismatching key algorithms");
- }
-
- if (keyAlgoOID.equals(OidMappings.sAlgo_RSA)) {
- if (keySize < MinRSAKeySize) {
- if (keySize >= 0) {
- Log.i(TAG, "Upgrading suggested RSA key size from " +
- keySize + " to " + MinRSAKeySize);
- }
- keySize = MinRSAKeySize;
- }
- }
-
- Log.d(TAG, String.format("pub key '%s', signature '%s', ECC curve '%s', id-atts %s",
- keyAlgo, sigAlgo, curveName, idAttributes));
-
- /*
- Ruckus:
- SEQUENCE:
- OID=1.2.840.113549.1.1.11 (algo_id_sha256WithRSAEncryption)
-
- RFC-7030:
- SEQUENCE:
- OID=1.2.840.113549.1.9.7 (challengePassword)
- SEQUENCE:
- OID=1.2.840.10045.2.1 (algo_id_ecPublicKey)
- SET:
- OID=1.3.132.0.34 (secp384r1)
- SEQUENCE:
- OID=1.2.840.113549.1.9.14 (extensionRequest)
- SET:
- OID=1.3.6.1.1.1.1.22 (mac-address)
- OID=1.2.840.10045.4.3.3 (eccdaWithSHA384)
-
- 1L, 3L, 6L, 1L, 1L, 1L, 1L, 22
- */
-
- // ECC Does not appear to be supported currently
- KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyAlgo);
- if (curveName != null) {
- AlgorithmParameters algorithmParameters = AlgorithmParameters.getInstance(keyAlgo);
- algorithmParameters.init(new ECNamedCurveGenParameterSpec(curveName));
- kpg.initialize(algorithmParameters
- .getParameterSpec(ECNamedCurveGenParameterSpec.class));
- } else {
- kpg.initialize(keySize);
- }
- KeyPair kp = kpg.generateKeyPair();
-
- X500Principal subject = new X500Principal("CN=Android, O=Google, C=US");
-
- mClientKey = kp.getPrivate();
-
- // !!! Map the idAttributes into an ASN1Set of values to pass to
- // the PKCS10CertificationRequest - this code is using outdated BC classes and
- // has *not* been tested.
- ASN1Set attributes;
- if (!idAttributes.isEmpty()) {
- ASN1EncodableVector payload = new DEREncodableVector();
- for (Map.Entry<Asn1Oid, ASN1Encodable> entry : idAttributes.entrySet()) {
- DERObjectIdentifier type = new DERObjectIdentifier(entry.getKey().toOIDString());
- ASN1Set values = new DERSet(entry.getValue());
- Attribute attribute = new Attribute(type, values);
- payload.add(attribute);
- }
- attributes = new DERSet(payload);
- } else {
- attributes = null;
- }
-
- return new PKCS10CertificationRequest(sigAlgo, subject, kp.getPublic(),
- attributes, mClientKey).getEncoded();
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/flow/FlowService.java b/packages/Osu/src/com/android/hotspot2/flow/FlowService.java
deleted file mode 100644
index 8bbbf06344d5..000000000000
--- a/packages/Osu/src/com/android/hotspot2/flow/FlowService.java
+++ /dev/null
@@ -1,168 +0,0 @@
-package com.android.hotspot2.flow;
-
-import android.annotation.Nullable;
-import android.app.IntentService;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.Network;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.os.IBinder;
-import android.util.Log;
-
-import com.android.hotspot2.osu.OSUFlowManager;
-import com.android.hotspot2.osu.OSUManager;
-import com.android.hotspot2.osu.OSUOperationStatus;
-import com.android.hotspot2.pps.HomeSP;
-
-import java.io.IOException;
-
-/**
- * This is the Hotspot 2.0 release 2 service that handles actual provisioning and remediation flows.
- *
- * The OSU App is made up of two services; FlowService and OSUService.
- *
- * OSUService is a long running light weight service, kept alive throughout the lifetime of the
- * operating system by being bound from the framework (in WifiManager in stage
- * PHASE_THIRD_PARTY_APPS_CAN_START), and is responsible for continuously caching OSU information
- * and notifying the UI when OSUs are available.
- *
- * FlowService is only started on demand from OSUService and is responsible for handling actual
- * provisioning and remediation flows, and requires a fairly significant memory footprint.
- *
- * FlowService is defined to run in its own process through the definition
- * <service android:name=".flow.FlowService" android:process=":osuflow">
- * in the AndroidManifest.
- * This is done as a means to keep total app memory footprint low (pss < 10M) and only start the
- * FlowService on demand and make it available for "garbage collection" by the OS when not in use.
- */
-public class FlowService extends IntentService {
- private static final String[] INTENTS = {
- WifiManager.NETWORK_STATE_CHANGED_ACTION
- };
-
- private OSUFlowManager mOSUFlowManager;
- private PlatformAdapter mPlatformAdapter;
- private final FlowServiceImpl mOSUAccessor = new FlowServiceImpl();
-
- /*
- public FlowService(Context context) {
- super("FlowService");
- mOSUFlowManager = new OSUFlowManager();
- mPlatformAdapter = new PlatformAdapter(context);
- BroadcastReceiver receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- handleIntent(intent.getAction(), intent);
- }
- };
- for (String intentString : INTENTS) {
- context.registerReceiver(receiver, new IntentFilter(intentString));
- }
- }
- */
-
- public FlowService() {
- super("FlowService");
- }
-
- public final class FlowServiceImpl extends IFlowService.Stub {
- public void provision(OSUInfo osuInfo) {
- FlowService.this.provision(osuInfo);
- }
-
- public void remediate(String spFqdn, String url, boolean policy, Network network) {
- FlowService.this.remediate(spFqdn, url, policy, network);
- }
-
- public void spDeleted(String fqdn) {
- FlowService.this.serviceProviderDeleted(fqdn);
- }
- }
-
- public void provision(OSUInfo osuInfo) {
- try {
- mOSUFlowManager.appendFlow(new OSUFlowManager.OSUFlow(osuInfo, mPlatformAdapter,
- mPlatformAdapter.getKeyManager(null)));
- } catch (IOException ioe) {
- mPlatformAdapter.notifyUser(OSUOperationStatus.ProvisioningFailure, ioe.getMessage(),
- osuInfo.getName(PlatformAdapter.LOCALE));
- }
- }
-
- /**
- * Initiate remediation
- * @param spFqdn The FQDN of the current SP, not set for WNM based remediation
- * @param url The URL of the remediation server
- * @param policy Set if this is a policy update rather than a subscription update
- * @param network The network to use for remediation
- */
- public void remediate(String spFqdn, String url, boolean policy, Network network) {
- Log.d(OSUManager.TAG, "Starting remediation for " + spFqdn + " to " + url);
- if (spFqdn != null) {
- HomeSP homeSP = mPlatformAdapter.getHomeSP(spFqdn);
- if (homeSP == null) {
- Log.e(OSUManager.TAG, "No HomeSP object matches '" + spFqdn + "'");
- return;
- }
-
- try {
- mOSUFlowManager.appendFlow(new OSUFlowManager.OSUFlow(network, url,
- mPlatformAdapter, mPlatformAdapter.getKeyManager(homeSP),
- homeSP, policy
- ? OSUFlowManager.FlowType.Policy : OSUFlowManager.FlowType.Remediation));
- } catch (IOException ioe) {
- Log.e(OSUManager.TAG, "Failed to remediate: " + ioe, ioe);
- }
- } else {
- HomeSP homeSP = mPlatformAdapter.getCurrentSP();
- if (homeSP == null) {
- Log.e(OSUManager.TAG, "Remediation request on unidentified Passpoint network ");
- return;
- }
-
- try {
- mOSUFlowManager.appendFlow(new OSUFlowManager.OSUFlow(network, url,
- mPlatformAdapter, mPlatformAdapter.getKeyManager(homeSP), homeSP,
- OSUFlowManager.FlowType.Remediation));
- } catch (IOException ioe) {
- Log.e(OSUManager.TAG, "Failed to start remediation: " + ioe, ioe);
- }
- }
- }
-
- public void serviceProviderDeleted(String fqdn) {
- mPlatformAdapter.serviceProviderDeleted(fqdn);
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- mOSUFlowManager = new OSUFlowManager(this);
- mPlatformAdapter = new PlatformAdapter(this);
- BroadcastReceiver receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- handleIntent(intent.getAction(), intent);
- }
- };
- for (String intentString : INTENTS) {
- registerReceiver(receiver, new IntentFilter(intentString));
- }
- return mOSUAccessor;
- }
-
- @Override
- protected void onHandleIntent(@Nullable Intent intent) {
- }
-
- private void handleIntent(String action, Intent intent) {
- if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
- WifiInfo wifiInfo = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
- if (wifiInfo != null) {
- mOSUFlowManager.networkChange();
- }
- }
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/flow/IFlowService.aidl b/packages/Osu/src/com/android/hotspot2/flow/IFlowService.aidl
deleted file mode 100644
index a61274fe8812..000000000000
--- a/packages/Osu/src/com/android/hotspot2/flow/IFlowService.aidl
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.android.hotspot2.flow;
-
-import com.android.hotspot2.flow.OSUInfo;
-import android.net.Network;
-
-interface IFlowService {
- void provision(in OSUInfo osuInfo);
- void remediate(String spFqdn, String url, boolean policy, in Network network);
- void spDeleted(String fqdn);
-}
diff --git a/packages/Osu/src/com/android/hotspot2/flow/OSUInfo.aidl b/packages/Osu/src/com/android/hotspot2/flow/OSUInfo.aidl
deleted file mode 100644
index 172486e3f3bf..000000000000
--- a/packages/Osu/src/com/android/hotspot2/flow/OSUInfo.aidl
+++ /dev/null
@@ -1,3 +0,0 @@
-package com.android.hotspot2.flow;
-
-parcelable OSUInfo;
diff --git a/packages/Osu/src/com/android/hotspot2/flow/OSUInfo.java b/packages/Osu/src/com/android/hotspot2/flow/OSUInfo.java
deleted file mode 100644
index 401eccb96d05..000000000000
--- a/packages/Osu/src/com/android/hotspot2/flow/OSUInfo.java
+++ /dev/null
@@ -1,321 +0,0 @@
-package com.android.hotspot2.flow;
-
-import android.net.wifi.ScanResult;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Log;
-
-import com.android.anqp.HSIconFileElement;
-import com.android.anqp.I18Name;
-import com.android.anqp.IconInfo;
-import com.android.anqp.OSUProvider;
-import com.android.hotspot2.Utils;
-import com.android.hotspot2.osu.OSUManager;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Locale;
-import java.util.Set;
-
-public class OSUInfo implements Parcelable {
- public static final String GenericLocale = "zxx";
-
- public enum IconStatus {
- NotQueried, //
- InProgress, // Query pending
- NotAvailable, // Deterministically unavailable
- Available // Icon data retrieved
- }
-
- private final long mBSSID;
- private final long mHESSID;
- private final int mAnqpDomID;
- private final String mAdvertisingSSID;
- private final OSUProvider mOSUProvider;
- private final int mOsuID;
- private long mOSUBssid;
- private IconStatus mIconStatus = IconStatus.NotQueried;
- private HSIconFileElement mIconFileElement;
- private String mIconFileName;
- private IconInfo mIconInfo;
-
- public OSUInfo(ScanResult scanResult, OSUProvider osuProvider, int osuID) {
- mOsuID = osuID;
- mBSSID = Utils.parseMac(scanResult.BSSID);
- mHESSID = scanResult.hessid;
- mAnqpDomID = scanResult.anqpDomainId;
- mAdvertisingSSID = scanResult.SSID;
- mOSUProvider = osuProvider;
- }
-
- public long getOSUBssid() {
- return mOSUBssid;
- }
-
- public void setOSUBssid(long OSUBssid) {
- mOSUBssid = OSUBssid;
- }
-
- public long getHESSID() {
- return mHESSID;
- }
-
- public int getAnqpDomID() {
- return mAnqpDomID;
- }
-
- public String getAdvertisingSsid() {
- return mAdvertisingSSID;
- }
-
- public Set<Locale> getNameLocales() {
- Set<Locale> locales = new HashSet<>(mOSUProvider.getNames().size());
- for (I18Name name : mOSUProvider.getNames()) {
- locales.add(name.getLocale());
- }
- return locales;
- }
-
- public Set<Locale> getServiceLocales() {
- Set<Locale> locales = new HashSet<>(mOSUProvider.getServiceDescriptions().size());
- for (I18Name name : mOSUProvider.getServiceDescriptions()) {
- locales.add(name.getLocale());
- }
- return locales;
- }
-
- public Set<String> getIconLanguages() {
- Set<String> locales = new HashSet<>(mOSUProvider.getIcons().size());
- for (IconInfo iconInfo : mOSUProvider.getIcons()) {
- locales.add(iconInfo.getLanguage());
- }
- return locales;
- }
-
- public String getName(Locale locale) {
- List<ScoreEntry<String>> scoreList = new ArrayList<>();
- for (I18Name name : mOSUProvider.getNames()) {
- if (locale == null || name.getLocale().equals(locale)) {
- return name.getText();
- }
- scoreList.add(new ScoreEntry<>(name.getText(),
- languageScore(name.getLanguage(), locale)));
- }
- Collections.sort(scoreList);
- return scoreList.isEmpty() ? null : scoreList.get(scoreList.size() - 1).getData();
- }
-
- public String getServiceDescription(Locale locale) {
- List<ScoreEntry<String>> scoreList = new ArrayList<>();
- for (I18Name service : mOSUProvider.getServiceDescriptions()) {
- if (locale == null || service.getLocale().equals(locale)) {
- return service.getText();
- }
- scoreList.add(new ScoreEntry<>(service.getText(),
- languageScore(service.getLanguage(), locale)));
- }
- Collections.sort(scoreList);
- return scoreList.isEmpty() ? null : scoreList.get(scoreList.size() - 1).getData();
- }
-
- public int getOsuID() {
- return mOsuID;
- }
-
- public void setIconStatus(IconStatus iconStatus) {
- synchronized (mOSUProvider) {
- mIconStatus = iconStatus;
- }
- }
-
- public IconStatus getIconStatus() {
- synchronized (mOSUProvider) {
- return mIconStatus;
- }
- }
-
- public HSIconFileElement getIconFileElement() {
- synchronized (mOSUProvider) {
- return mIconFileElement;
- }
- }
-
- public IconInfo getIconInfo() {
- synchronized (mOSUProvider) {
- return mIconInfo;
- }
- }
-
- public String getIconFileName() {
- return mIconFileName;
- }
-
- public void setIconFileElement(HSIconFileElement iconFileElement, String fileName) {
- synchronized (mOSUProvider) {
- mIconFileElement = iconFileElement;
- for (IconInfo iconInfo : mOSUProvider.getIcons()) {
- if (iconInfo.getFileName().equals(fileName)) {
- mIconInfo = iconInfo;
- mIconFileName = fileName;
- break;
- }
- }
- mIconStatus = IconStatus.Available;
- }
- }
-
- private static class ScoreEntry<T> implements Comparable<ScoreEntry> {
- private final T mData;
- private final int mScore;
-
- private ScoreEntry(T data, int score) {
- mData = data;
- mScore = score;
- }
-
- public T getData() {
- return mData;
- }
-
- @Override
- public int compareTo(ScoreEntry other) {
- return Integer.compare(mScore, other.mScore);
- }
-
- @Override
- public String toString() {
- return String.format("%d for '%s'", mScore, mData);
- }
- }
-
- public List<IconInfo> getIconInfo(Locale locale, Set<String> types, int width, int height) {
- if (mOSUProvider.getIcons().isEmpty()) {
- return null;
- }
- Log.d(OSUManager.TAG, "Matching icons against " + locale
- + ", types " + types + ", " + width + "*" + height);
-
- List<ScoreEntry<IconInfo>> matches = new ArrayList<>();
- for (IconInfo iconInfo : mOSUProvider.getIcons()) {
- Log.d(OSUManager.TAG, "Checking icon " + iconInfo.toString());
- if (!types.contains(iconInfo.getIconType())) {
- continue;
- }
-
- int score = languageScore(iconInfo.getLanguage(), locale);
- int delta = iconInfo.getWidth() - width;
- // Best size score is 1024 for a exact match, i.e. 2048 if both sides match
- if (delta >= 0) {
- score += (256 - delta) * 4; // Prefer down-scaling
- } else {
- score += 256 + delta; // Before up-scaling
- }
- delta = iconInfo.getHeight() - height;
- if (delta >= 0) {
- score += (256 - delta) * 4;
- } else {
- score += 256 + delta;
- }
- matches.add(new ScoreEntry<>(iconInfo, score));
- }
- if (matches.isEmpty()) {
- return Collections.emptyList();
- }
- Collections.sort(matches);
- List<IconInfo> icons = new ArrayList<>(matches.size());
- ListIterator<ScoreEntry<IconInfo>> matchIterator = matches.listIterator(matches.size());
- while (matchIterator.hasPrevious()) {
- icons.add(matchIterator.previous().getData());
- }
- return icons;
- }
-
- private static int languageScore(String language, Locale locale) {
- if (language.length() == 3 && language.equalsIgnoreCase(locale.getISO3Language()) ||
- language.length() == 2 && language.equalsIgnoreCase(locale.getLanguage())) {
- return 4096;
- } else if (language.equalsIgnoreCase(GenericLocale)) {
- return 3072;
- } else if (language.equalsIgnoreCase("eng")) {
- return 2048;
- } else {
- return 1024;
- }
- }
-
- public long getBSSID() {
- return mBSSID;
- }
-
- public String getOsuSsid() {
- return mOSUProvider.getSSID();
- }
-
- public OSUProvider getOSUProvider() {
- return mOSUProvider;
- }
-
- @Override
- public String toString() {
- return String.format("OSU Info '%s' %012x -> %s, icon %s",
- getOsuSsid(), mBSSID, getServiceDescription(null), mIconStatus);
- }
-
- private OSUInfo(Parcel in) {
- mBSSID = in.readLong();
- mHESSID = in.readLong();
- mAnqpDomID = in.readInt();
- mAdvertisingSSID = in.readString();
- mOsuID = in.readInt();
- mOSUBssid = in.readLong();
- mIconFileName = in.readString();
- mIconStatus = Utils.mapEnum(in.readInt(), IconStatus.class);
- OSUProvider osuProvider;
- try {
- osuProvider = new OSUProvider(in);
- } catch (IOException ioe) {
- osuProvider = null;
- }
- mOSUProvider = osuProvider;
- if (osuProvider == null) {
- return;
- }
- mIconFileElement = new HSIconFileElement(in);
- int iconIndex = in.readInt();
- mIconInfo = iconIndex >= 0 && iconIndex < mOSUProvider.getIcons().size()
- ? mOSUProvider.getIcons().get(iconIndex) : null;
- }
-
- public static final Parcelable.Creator<OSUInfo> CREATOR = new Parcelable.Creator<OSUInfo>() {
- public OSUInfo createFromParcel(Parcel in) {
- return new OSUInfo(in);
- }
-
- public OSUInfo[] newArray(int size) {
- return new OSUInfo[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeLong(mBSSID);
- dest.writeLong(mHESSID);
- dest.writeInt(mAnqpDomID);
- dest.writeString(mAdvertisingSSID);
- dest.writeInt(mOsuID);
- dest.writeLong(mOSUBssid);
- dest.writeString(mIconFileName);
- dest.writeInt(mIconStatus.ordinal());
- mOSUProvider.writeParcel(dest);
- mIconFileElement.writeParcel(dest);
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/flow/PlatformAdapter.java b/packages/Osu/src/com/android/hotspot2/flow/PlatformAdapter.java
deleted file mode 100644
index d95af61a27c1..000000000000
--- a/packages/Osu/src/com/android/hotspot2/flow/PlatformAdapter.java
+++ /dev/null
@@ -1,620 +0,0 @@
-package com.android.hotspot2.flow;
-
-import android.content.Context;
-import android.content.Intent;
-import android.net.Network;
-import android.net.wifi.PasspointManagementObjectDefinition;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiEnterpriseConfig;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.util.Log;
-
-import com.android.configparse.ConfigBuilder;
-import com.android.hotspot2.AppBridge;
-import com.android.hotspot2.Utils;
-import com.android.hotspot2.app.OSUService;
-import com.android.hotspot2.omadm.MOManager;
-import com.android.hotspot2.omadm.MOTree;
-import com.android.hotspot2.omadm.OMAConstants;
-import com.android.hotspot2.omadm.OMAException;
-import com.android.hotspot2.omadm.OMAParser;
-import com.android.hotspot2.osu.ClientKeyManager;
-import com.android.hotspot2.osu.OSUCertType;
-import com.android.hotspot2.osu.OSUManager;
-import com.android.hotspot2.osu.OSUOperationStatus;
-import com.android.hotspot2.osu.OSUSocketFactory;
-import com.android.hotspot2.osu.WiFiKeyManager;
-import com.android.hotspot2.osu.commands.MOData;
-import com.android.hotspot2.pps.HomeSP;
-
-import org.xml.sax.SAXException;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.security.GeneralSecurityException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.PrivateKey;
-import java.security.cert.Certificate;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-import javax.net.ssl.KeyManager;
-
-public class PlatformAdapter {
- private static final String TAG = "OSUFLOW";
-
- public static final Locale LOCALE = Locale.getDefault();
-
- public static final String CERT_WFA_ALIAS = "wfa-root-";
- public static final String CERT_REM_ALIAS = "rem-";
- public static final String CERT_POLICY_ALIAS = "pol-";
- public static final String CERT_SHARED_ALIAS = "shr-";
- public static final String CERT_CLT_CERT_ALIAS = "clt-";
- public static final String CERT_CLT_KEY_ALIAS = "prv-";
- public static final String CERT_CLT_CA_ALIAS = "aaa-";
-
- private static final String KEYSTORE_FILE = "passpoint.ks";
-
- private final Context mContext;
- private final File mKeyStoreFile;
- private final KeyStore mKeyStore;
- private final AppBridge mAppBridge;
- private final Map<String, PasspointConfig> mPasspointConfigs;
-
- public PlatformAdapter(Context context) {
- mContext = context;
- mAppBridge = new AppBridge(context);
-
- File appFolder = context.getFilesDir();
- mKeyStoreFile = new File(appFolder, KEYSTORE_FILE);
- Log.d(TAG, "KS file: " + mKeyStoreFile.getPath());
- KeyStore ks = null;
- try {
- //ks = loadKeyStore(KEYSTORE_FILE, readCertsFromDisk(WFA_CA_LOC));
- ks = loadKeyStore(mKeyStoreFile, OSUSocketFactory.buildCertSet());
- } catch (IOException e) {
- Log.e(TAG, "Failed to initialize Passpoint keystore, OSU disabled", e);
- }
- mKeyStore = ks;
-
- mPasspointConfigs = loadAllSps(context);
- }
-
- private static KeyStore loadKeyStore(File ksFile, Set<X509Certificate> diskCerts)
- throws IOException {
- try {
- KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
- if (ksFile.exists()) {
- try (FileInputStream in = new FileInputStream(ksFile)) {
- keyStore.load(in, null);
- }
-
- // Note: comparing two sets of certs does not work.
- boolean mismatch = false;
- int loadCount = 0;
- for (int n = 0; n < 1000; n++) {
- String alias = String.format("%s%d", CERT_WFA_ALIAS, n);
- Certificate cert = keyStore.getCertificate(alias);
- if (cert == null) {
- break;
- }
-
- loadCount++;
- boolean matched = false;
- Iterator<X509Certificate> iter = diskCerts.iterator();
- while (iter.hasNext()) {
- X509Certificate diskCert = iter.next();
- if (cert.equals(diskCert)) {
- iter.remove();
- matched = true;
- break;
- }
- }
- if (!matched) {
- mismatch = true;
- break;
- }
- }
- if (mismatch || !diskCerts.isEmpty()) {
- Log.d(TAG, "Re-seeding Passpoint key store with " +
- diskCerts.size() + " WFA certs");
- for (int n = 0; n < 1000; n++) {
- String alias = String.format("%s%d", CERT_WFA_ALIAS, n);
- Certificate cert = keyStore.getCertificate(alias);
- if (cert == null) {
- break;
- } else {
- keyStore.deleteEntry(alias);
- }
- }
- int index = 0;
- for (X509Certificate caCert : diskCerts) {
- keyStore.setCertificateEntry(
- String.format("%s%d", CERT_WFA_ALIAS, index), caCert);
- index++;
- }
-
- try (FileOutputStream out = new FileOutputStream(ksFile)) {
- keyStore.store(out, null);
- }
- } else {
- Log.d(TAG, "Loaded Passpoint key store with " + loadCount + " CA certs");
- Enumeration<String> aliases = keyStore.aliases();
- while (aliases.hasMoreElements()) {
- Log.d("ZXC", "KS Alias '" + aliases.nextElement() + "'");
- }
- }
- } else {
- keyStore.load(null, null);
- int index = 0;
- for (X509Certificate caCert : diskCerts) {
- keyStore.setCertificateEntry(
- String.format("%s%d", CERT_WFA_ALIAS, index), caCert);
- index++;
- }
-
- try (FileOutputStream out = new FileOutputStream(ksFile)) {
- keyStore.store(out, null);
- }
- Log.d(TAG, "Initialized Passpoint key store with " +
- diskCerts.size() + " CA certs");
- }
- return keyStore;
- } catch (GeneralSecurityException gse) {
- throw new IOException(gse);
- }
- }
-
- private static Map<String, PasspointConfig> loadAllSps(Context context) {
- Map<String, PasspointConfig> passpointConfigs = new HashMap<>();
-
- WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
- List<WifiConfiguration> configs = wifiManager.getPrivilegedConfiguredNetworks();
- if (configs == null) {
- return passpointConfigs;
- }
- int count = 0;
- for (WifiConfiguration config : configs) {
- String moTree = config.getMoTree();
- if (moTree != null) {
- try {
- passpointConfigs.put(config.FQDN, new PasspointConfig(config));
- count++;
- } catch (IOException | SAXException e) {
- Log.w(OSUManager.TAG, "Failed to parse MO: " + e);
- }
- }
- }
- Log.d(OSUManager.TAG, "Loaded " + count + " SPs");
- return passpointConfigs;
- }
-
- public KeyStore getKeyStore() {
- return mKeyStore;
- }
-
- public Context getContext() {
- return mContext;
- }
-
- /**
- * Connect to an OSU provisioning network. The connection should not bring down other existing
- * connection and the network should not be made the default network since the connection
- * is solely for sign up and is neither intended for nor likely provides access to any
- * generic resources.
- *
- * @param osuInfo The OSU info object that defines the parameters for the network. An OSU
- * network is either an open network, or, if the OSU NAI is set, an "OSEN"
- * network, which is an anonymous EAP-TLS network with special keys.
- * @return an Integer holding the network-id of the just added network configuration, or null
- * if the network existed prior to this call (was not added by the OSU infrastructure).
- * The value will be used at the end of the OSU flow to delete the network as applicable.
- * @throws IOException Issues:
- * 1. The network id is not returned. addNetwork cannot be called from here since the method
- * runs in the context of the app and doesn't have the appropriate permission.
- * 2. The connection is not immediately usable if the network was not previously selected
- * manually.
- */
- public Integer connect(OSUInfo osuInfo) throws IOException {
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
-
- WifiConfiguration config = new WifiConfiguration();
- config.SSID = '"' + osuInfo.getOsuSsid() + '"';
- if (osuInfo.getOSUBssid() != 0) {
- config.BSSID = Utils.macToString(osuInfo.getOSUBssid());
- Log.d(OSUManager.TAG, String.format("Setting BSSID of '%s' to %012x",
- osuInfo.getOsuSsid(), osuInfo.getOSUBssid()));
- }
-
- if (osuInfo.getOSUProvider().getOsuNai() == null) {
- config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
- } else {
- config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OSEN);
- config.allowedProtocols.set(WifiConfiguration.Protocol.OSEN);
- config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
- config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GTK_NOT_USED);
- config.enterpriseConfig = new WifiEnterpriseConfig();
- config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.UNAUTH_TLS);
- config.enterpriseConfig.setIdentity(osuInfo.getOSUProvider().getOsuNai());
- Set<X509Certificate> cas = OSUSocketFactory.buildCertSet();
- config.enterpriseConfig.setCaCertificates(cas.toArray(new X509Certificate[cas.size()]));
- }
-
- int networkId = wifiManager.addNetwork(config);
- if (networkId < 0) {
- throw new IOException("Failed to add OSU network");
- }
- if (wifiManager.enableNetwork(networkId, true)) {
- return networkId;
- } else {
- throw new IOException("Failed to enable OSU network");
- }
- }
-
- /**
- * @param homeSP The Home SP associated with the keying material in question. Passing
- * null returns a "system wide" KeyManager to support pre-provisioned certs based
- * on names retrieved from the ClientCertInfo request.
- * @return A key manager suitable for the given configuration (or pre-provisioned keys).
- */
- public KeyManager getKeyManager(HomeSP homeSP) throws IOException {
- return homeSP != null
- ? new ClientKeyManager(homeSP, mKeyStore) : new WiFiKeyManager(mKeyStore);
- }
-
- public void provisioningComplete(OSUInfo osuInfo,
- MOData moData, Map<OSUCertType, List<X509Certificate>> certs,
- PrivateKey privateKey, Network osuNetwork) {
- try {
- String xml = moData.getMOTree().toXml();
- HomeSP homeSP = MOManager.buildSP(xml);
-
- Integer spNwk = addNetwork(homeSP, certs, privateKey, osuNetwork);
- if (spNwk == null) {
- notifyUser(OSUOperationStatus.ProvisioningFailure,
- "Failed to save network configuration", osuInfo.getName(LOCALE));
- } else {
- if (addSP(xml) < 0) {
- deleteNetwork(spNwk);
- Log.e(TAG, "Failed to provision: " + homeSP.getFQDN());
- notifyUser(OSUOperationStatus.ProvisioningFailure, "Failed to add MO",
- osuInfo.getName(LOCALE));
- return;
- }
- Set<X509Certificate> rootCerts = OSUSocketFactory.getRootCerts(mKeyStore);
- X509Certificate remCert = getCert(certs, OSUCertType.Remediation);
- X509Certificate polCert = getCert(certs, OSUCertType.Policy);
- int newCerts = 0;
- if (privateKey != null) {
- X509Certificate cltCert = getCert(certs, OSUCertType.Client);
- mKeyStore.setKeyEntry(CERT_CLT_KEY_ALIAS + homeSP.getFQDN(),
- privateKey, null, new X509Certificate[]{cltCert});
- mKeyStore.setCertificateEntry(CERT_CLT_CERT_ALIAS + homeSP.getFQDN(), cltCert);
- newCerts++;
- }
- boolean usingShared = false;
- if (remCert != null) {
- if (!rootCerts.contains(remCert)) {
- if (remCert.equals(polCert)) {
- mKeyStore.setCertificateEntry(CERT_SHARED_ALIAS + homeSP.getFQDN(),
- remCert);
- usingShared = true;
- newCerts++;
- } else {
- mKeyStore.setCertificateEntry(CERT_REM_ALIAS + homeSP.getFQDN(),
- remCert);
- newCerts++;
- }
- }
- }
- if (!usingShared && polCert != null) {
- if (!rootCerts.contains(polCert)) {
- mKeyStore.setCertificateEntry(CERT_POLICY_ALIAS + homeSP.getFQDN(),
- remCert);
- newCerts++;
- }
- }
-
-
- if (newCerts > 0) {
- try (FileOutputStream out = new FileOutputStream(mKeyStoreFile)) {
- mKeyStore.store(out, null);
- }
- }
- notifyUser(OSUOperationStatus.ProvisioningSuccess, null, osuInfo.getName(LOCALE));
- Log.d(TAG, "Provisioning complete.");
- }
- } catch (IOException | GeneralSecurityException | SAXException e) {
- Log.e(TAG, "Failed to provision: " + e, e);
- notifyUser(OSUOperationStatus.ProvisioningFailure, e.toString(),
- osuInfo.getName(LOCALE));
- }
- }
-
- public void remediationComplete(HomeSP homeSP, Collection<MOData> mods,
- Map<OSUCertType, List<X509Certificate>> certs,
- PrivateKey privateKey, boolean policy)
- throws IOException, GeneralSecurityException {
-
- HomeSP altSP = null;
- if (modifySP(homeSP, mods) > 0) {
- altSP = MOManager.modifySP(homeSP, getMOTree(homeSP), mods);
- }
-
- X509Certificate caCert = null;
- List<X509Certificate> clientCerts = null;
- if (certs != null) {
- List<X509Certificate> certList = certs.get(OSUCertType.AAA);
- caCert = certList != null && !certList.isEmpty() ? certList.iterator().next() : null;
- clientCerts = certs.get(OSUCertType.Client);
- }
- if (altSP != null || certs != null) {
- if (altSP == null) {
- altSP = homeSP;
- }
- updateNetwork(altSP, caCert, clientCerts, privateKey);
-
- if (privateKey != null) {
- X509Certificate cltCert = getCert(certs, OSUCertType.Client);
- mKeyStore.setKeyEntry(CERT_CLT_KEY_ALIAS + homeSP.getFQDN(),
- privateKey, null, new X509Certificate[]{cltCert});
- mKeyStore.setCertificateEntry(CERT_CLT_CERT_ALIAS + homeSP.getFQDN(), cltCert);
- }
- }
-
- Intent intent = new Intent(OSUService.REMEDIATION_DONE_ACTION);
- intent.putExtra(OSUService.REMEDIATION_FQDN_EXTRA, homeSP.getFQDN());
- intent.putExtra(OSUService.REMEDIATION_POLICY_EXTRA, policy);
- mContext.sendBroadcast(intent);
-
- notifyUser(OSUOperationStatus.ProvisioningSuccess, null, homeSP.getFriendlyName());
- }
-
- public void serviceProviderDeleted(String fqdn) {
- int count = deleteCerts(mKeyStore, fqdn,
- CERT_REM_ALIAS, CERT_POLICY_ALIAS, CERT_SHARED_ALIAS, CERT_CLT_CERT_ALIAS);
-
- Log.d(TAG, "Passpoint network deleted, removing " + count + " key store entries");
-
- try {
- if (mKeyStore.getKey(CERT_CLT_KEY_ALIAS + fqdn, null) != null) {
- mKeyStore.deleteEntry(CERT_CLT_KEY_ALIAS + fqdn);
- }
- } catch (GeneralSecurityException e) {
- /**/
- }
-
- if (count > 0) {
- try (FileOutputStream out = new FileOutputStream(mKeyStoreFile)) {
- mKeyStore.store(out, null);
- } catch (IOException | GeneralSecurityException e) {
- Log.w(TAG, "Failed to remove certs from key store: " + e);
- }
- }
- }
-
- private static int deleteCerts(KeyStore keyStore, String fqdn, String... prefixes) {
- int count = 0;
- for (String prefix : prefixes) {
- try {
- String alias = prefix + fqdn;
- Certificate cert = keyStore.getCertificate(alias);
- if (cert != null) {
- keyStore.deleteEntry(alias);
- count++;
- }
- } catch (KeyStoreException kse) {
- /**/
- }
- }
- return count;
- }
-
- private static X509Certificate getCert(Map<OSUCertType, List<X509Certificate>> certMap,
- OSUCertType certType) {
- List<X509Certificate> certs = certMap.get(certType);
- if (certs == null || certs.isEmpty()) {
- return null;
- }
- return certs.iterator().next();
- }
-
- public String notifyUser(OSUOperationStatus status, String message, String spName) {
- if (status == OSUOperationStatus.UserInputComplete) {
- return null;
- }
- mAppBridge.showStatus(status, spName, message, null);
- return null;
- }
-
- public void provisioningFailed(String spName, String message) {
- notifyUser(OSUOperationStatus.ProvisioningFailure, message, spName);
- }
-
- private Integer addNetwork(HomeSP homeSP, Map<OSUCertType, List<X509Certificate>> certs,
- PrivateKey privateKey, Network osuNetwork)
- throws IOException, GeneralSecurityException {
-
- List<X509Certificate> aaaTrust = certs.get(OSUCertType.AAA);
- if (aaaTrust.isEmpty()) {
- aaaTrust = certs.get(OSUCertType.CA); // Get the CAs from the EST flow.
- }
-
- WifiConfiguration config = ConfigBuilder.buildConfig(homeSP,
- aaaTrust.iterator().next(),
- certs.get(OSUCertType.Client), privateKey);
-
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- int nwkId = wifiManager.addNetwork(config);
- boolean saved = false;
- if (nwkId >= 0) {
- saved = wifiManager.saveConfiguration();
- }
- Log.d(OSUManager.TAG, "Wifi configuration " + nwkId +
- " " + (saved ? "saved" : "not saved"));
-
- if (saved) {
- reconnect(osuNetwork, nwkId);
- return nwkId;
- } else {
- return null;
- }
- }
-
- private void updateNetwork(HomeSP homeSP, X509Certificate caCert,
- List<X509Certificate> clientCerts, PrivateKey privateKey)
- throws IOException, GeneralSecurityException {
-
- WifiConfiguration config = getWifiConfig(homeSP);
- if (config == null) {
- throw new IOException("Failed to find matching network config");
- }
- Log.d(OSUManager.TAG, "Found matching config " + config.networkId + ", updating");
-
- WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
- WifiConfiguration newConfig = ConfigBuilder.buildConfig(homeSP,
- caCert != null ? caCert : enterpriseConfig.getCaCertificate(),
- clientCerts, privateKey);
- newConfig.networkId = config.networkId;
-
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- wifiManager.save(newConfig, null);
- wifiManager.saveConfiguration();
- }
-
- private WifiConfiguration getWifiConfig(HomeSP homeSP) {
- PasspointConfig passpointConfig = mPasspointConfigs.get(homeSP.getFQDN());
- return passpointConfig != null ? passpointConfig.getWifiConfiguration() : null;
- }
-
- public MOTree getMOTree(HomeSP homeSP) {
- PasspointConfig config = mPasspointConfigs.get(homeSP.getFQDN());
- return config != null ? config.getmMOTree() : null;
- }
-
- public HomeSP getHomeSP(String fqdn) {
- PasspointConfig passpointConfig = mPasspointConfigs.get(fqdn);
- return passpointConfig != null ? passpointConfig.getHomeSP() : null;
- }
-
- public HomeSP getCurrentSP() {
- PasspointConfig passpointConfig = getActivePasspointConfig();
- return passpointConfig != null ? passpointConfig.getHomeSP() : null;
- }
-
- private PasspointConfig getActivePasspointConfig() {
- WifiInfo wifiInfo = getConnectionInfo();
- if (wifiInfo == null) {
- return null;
- }
-
- for (PasspointConfig passpointConfig : mPasspointConfigs.values()) {
- if (passpointConfig.getWifiConfiguration().networkId == wifiInfo.getNetworkId()) {
- return passpointConfig;
- }
- }
- return null;
- }
-
- private int addSP(String xml) throws IOException, SAXException {
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- // TODO(b/32883320): use the new API for adding Passpoint configuration.
- return 0;
- }
-
- private int modifySP(HomeSP homeSP, Collection<MOData> mods) throws IOException {
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- List<PasspointManagementObjectDefinition> defMods = new ArrayList<>(mods.size());
- for (MOData mod : mods) {
- defMods.add(new PasspointManagementObjectDefinition(mod.getBaseURI(),
- mod.getURN(), mod.getMOTree().toXml()));
- }
- // TODO(b/32883320): use the new API to update Passpoint configuration.
- return 0;
- }
-
- private void reconnect(Network osuNetwork, int newNwkId) {
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- if (osuNetwork != null) {
- wifiManager.disableNetwork(osuNetwork.netId);
- }
- if (newNwkId != WifiConfiguration.INVALID_NETWORK_ID) {
- wifiManager.enableNetwork(newNwkId, true);
- }
- }
-
- public void deleteNetwork(int id) {
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- wifiManager.disableNetwork(id);
- wifiManager.forget(id, null);
- }
-
- public WifiInfo getConnectionInfo() {
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- return wifiManager.getConnectionInfo();
- }
-
- public Network getCurrentNetwork() {
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- return wifiManager.getCurrentNetwork();
- }
-
- public WifiConfiguration getActiveWifiConfig() {
- WifiInfo wifiInfo = getConnectionInfo();
- if (wifiInfo == null) {
- return null;
- }
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- List<WifiConfiguration> configs = wifiManager.getConfiguredNetworks();
- if (configs == null) {
- return null;
- }
- for (WifiConfiguration config : configs) {
- if (config.networkId == wifiInfo.getNetworkId()) {
- return config;
- }
- }
- return null;
- }
-
- private static class PasspointConfig {
- private final WifiConfiguration mWifiConfiguration;
- private final MOTree mMOTree;
- private final HomeSP mHomeSP;
-
- private PasspointConfig(WifiConfiguration config) throws IOException, SAXException {
- mWifiConfiguration = config;
- OMAParser omaParser = new OMAParser();
- mMOTree = omaParser.parse(config.getMoTree(), OMAConstants.PPS_URN);
- List<HomeSP> spList = MOManager.buildSPs(mMOTree);
- if (spList.size() != 1) {
- throw new OMAException("Expected exactly one HomeSP, got " + spList.size());
- }
- mHomeSP = spList.iterator().next();
- }
-
- public WifiConfiguration getWifiConfiguration() {
- return mWifiConfiguration;
- }
-
- public HomeSP getHomeSP() {
- return mHomeSP;
- }
-
- public MOTree getmMOTree() {
- return mMOTree;
- }
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/omadm/MOManager.java b/packages/Osu/src/com/android/hotspot2/omadm/MOManager.java
deleted file mode 100644
index 8a1eef4463da..000000000000
--- a/packages/Osu/src/com/android/hotspot2/omadm/MOManager.java
+++ /dev/null
@@ -1,1037 +0,0 @@
-package com.android.hotspot2.omadm;
-
-import android.util.Base64;
-import android.util.Log;
-
-import com.android.anqp.eap.EAP;
-import com.android.anqp.eap.EAPMethod;
-import com.android.anqp.eap.ExpandedEAPMethod;
-import com.android.anqp.eap.InnerAuthEAP;
-import com.android.anqp.eap.NonEAPInnerAuth;
-import com.android.hotspot2.IMSIParameter;
-import com.android.hotspot2.Utils;
-import com.android.hotspot2.osu.OSUManager;
-import com.android.hotspot2.osu.commands.MOData;
-import com.android.hotspot2.pps.Credential;
-import com.android.hotspot2.pps.HomeSP;
-import com.android.hotspot2.pps.Policy;
-import com.android.hotspot2.pps.SubscriptionParameters;
-import com.android.hotspot2.pps.UpdateInfo;
-
-import org.xml.sax.SAXException;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TimeZone;
-
-/**
- * Handles provisioning of PerProviderSubscription data.
- */
-public class MOManager {
-
- public static final String TAG_AAAServerTrustRoot = "AAAServerTrustRoot";
- public static final String TAG_AbleToShare = "AbleToShare";
- public static final String TAG_CertificateType = "CertificateType";
- public static final String TAG_CertSHA256Fingerprint = "CertSHA256Fingerprint";
- public static final String TAG_CertURL = "CertURL";
- public static final String TAG_CheckAAAServerCertStatus = "CheckAAAServerCertStatus";
- public static final String TAG_Country = "Country";
- public static final String TAG_CreationDate = "CreationDate";
- public static final String TAG_Credential = "Credential";
- public static final String TAG_CredentialPriority = "CredentialPriority";
- public static final String TAG_DataLimit = "DataLimit";
- public static final String TAG_DigitalCertificate = "DigitalCertificate";
- public static final String TAG_DLBandwidth = "DLBandwidth";
- public static final String TAG_EAPMethod = "EAPMethod";
- public static final String TAG_EAPType = "EAPType";
- public static final String TAG_ExpirationDate = "ExpirationDate";
- public static final String TAG_Extension = "Extension";
- public static final String TAG_FQDN = "FQDN";
- public static final String TAG_FQDN_Match = "FQDN_Match";
- public static final String TAG_FriendlyName = "FriendlyName";
- public static final String TAG_HESSID = "HESSID";
- public static final String TAG_HomeOI = "HomeOI";
- public static final String TAG_HomeOIList = "HomeOIList";
- public static final String TAG_HomeOIRequired = "HomeOIRequired";
- public static final String TAG_HomeSP = "HomeSP";
- public static final String TAG_IconURL = "IconURL";
- public static final String TAG_IMSI = "IMSI";
- public static final String TAG_InnerEAPType = "InnerEAPType";
- public static final String TAG_InnerMethod = "InnerMethod";
- public static final String TAG_InnerVendorID = "InnerVendorID";
- public static final String TAG_InnerVendorType = "InnerVendorType";
- public static final String TAG_IPProtocol = "IPProtocol";
- public static final String TAG_MachineManaged = "MachineManaged";
- public static final String TAG_MaximumBSSLoadValue = "MaximumBSSLoadValue";
- public static final String TAG_MinBackhaulThreshold = "MinBackhaulThreshold";
- public static final String TAG_NetworkID = "NetworkID";
- public static final String TAG_NetworkType = "NetworkType";
- public static final String TAG_Other = "Other";
- public static final String TAG_OtherHomePartners = "OtherHomePartners";
- public static final String TAG_Password = "Password";
- public static final String TAG_PerProviderSubscription = "PerProviderSubscription";
- public static final String TAG_Policy = "Policy";
- public static final String TAG_PolicyUpdate = "PolicyUpdate";
- public static final String TAG_PortNumber = "PortNumber";
- public static final String TAG_PreferredRoamingPartnerList = "PreferredRoamingPartnerList";
- public static final String TAG_Priority = "Priority";
- public static final String TAG_Realm = "Realm";
- public static final String TAG_RequiredProtoPortTuple = "RequiredProtoPortTuple";
- public static final String TAG_Restriction = "Restriction";
- public static final String TAG_RoamingConsortiumOI = "RoamingConsortiumOI";
- public static final String TAG_SIM = "SIM";
- public static final String TAG_SoftTokenApp = "SoftTokenApp";
- public static final String TAG_SPExclusionList = "SPExclusionList";
- public static final String TAG_SSID = "SSID";
- public static final String TAG_StartDate = "StartDate";
- public static final String TAG_SubscriptionParameters = "SubscriptionParameters";
- public static final String TAG_SubscriptionUpdate = "SubscriptionUpdate";
- public static final String TAG_TimeLimit = "TimeLimit";
- public static final String TAG_TrustRoot = "TrustRoot";
- public static final String TAG_TypeOfSubscription = "TypeOfSubscription";
- public static final String TAG_ULBandwidth = "ULBandwidth";
- public static final String TAG_UpdateIdentifier = "UpdateIdentifier";
- public static final String TAG_UpdateInterval = "UpdateInterval";
- public static final String TAG_UpdateMethod = "UpdateMethod";
- public static final String TAG_URI = "URI";
- public static final String TAG_UsageLimits = "UsageLimits";
- public static final String TAG_UsageTimePeriod = "UsageTimePeriod";
- public static final String TAG_Username = "Username";
- public static final String TAG_UsernamePassword = "UsernamePassword";
- public static final String TAG_VendorId = "VendorId";
- public static final String TAG_VendorType = "VendorType";
-
- public static final long IntervalFactor = 60000L; // All MO intervals are in minutes
-
- private static final DateFormat DTFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
-
- private static final Map<String, Map<String, Object>> sSelectionMap;
-
- static {
- DTFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
-
- sSelectionMap = new HashMap<>();
-
- setSelections(TAG_FQDN_Match,
- "exactmatch", Boolean.FALSE,
- "includesubdomains", Boolean.TRUE);
- setSelections(TAG_UpdateMethod,
- "oma-dm-clientinitiated", Boolean.FALSE,
- "spp-clientinitiated", Boolean.TRUE);
- setSelections(TAG_Restriction,
- "homesp", UpdateInfo.UpdateRestriction.HomeSP,
- "roamingpartner", UpdateInfo.UpdateRestriction.RoamingPartner,
- "unrestricted", UpdateInfo.UpdateRestriction.Unrestricted);
- }
-
- private static void setSelections(String key, Object... pairs) {
- Map<String, Object> kvp = new HashMap<>();
- sSelectionMap.put(key, kvp);
- for (int n = 0; n < pairs.length; n += 2) {
- kvp.put(pairs[n].toString(), pairs[n + 1]);
- }
- }
-
- private final File mPpsFile;
- private final boolean mEnabled;
- private final Map<String, HomeSP> mSPs;
-
- public MOManager(File ppsFile, boolean hs2enabled) {
- mPpsFile = ppsFile;
- mEnabled = hs2enabled;
- mSPs = new HashMap<>();
- }
-
- public File getPpsFile() {
- return mPpsFile;
- }
-
- public boolean isEnabled() {
- return mEnabled;
- }
-
- public boolean isConfigured() {
- return mEnabled && !mSPs.isEmpty();
- }
-
- public Map<String, HomeSP> getLoadedSPs() {
- return Collections.unmodifiableMap(mSPs);
- }
-
- public List<HomeSP> loadAllSPs() throws IOException {
-
- if (!mEnabled || !mPpsFile.exists()) {
- return Collections.emptyList();
- }
-
- try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(mPpsFile))) {
- MOTree moTree = MOTree.unmarshal(in);
- mSPs.clear();
- if (moTree == null) {
- return Collections.emptyList(); // Empty file
- }
-
- List<HomeSP> sps = buildSPs(moTree);
- if (sps != null) {
- for (HomeSP sp : sps) {
- if (mSPs.put(sp.getFQDN(), sp) != null) {
- throw new OMAException("Multiple SPs for FQDN '" + sp.getFQDN() + "'");
- } else {
- Log.d(OSUManager.TAG, "retrieved " + sp.getFQDN() + " from PPS");
- }
- }
- return sps;
-
- } else {
- throw new OMAException("Failed to build HomeSP");
- }
- }
- }
-
- public static HomeSP buildSP(String xml) throws IOException, SAXException {
- OMAParser omaParser = new OMAParser();
- MOTree tree = omaParser.parse(xml, OMAConstants.PPS_URN);
- List<HomeSP> spList = buildSPs(tree);
- if (spList.size() != 1) {
- throw new OMAException("Expected exactly one HomeSP, got " + spList.size());
- }
- return spList.iterator().next();
- }
-
- public HomeSP addSP(String xml, OSUManager osuManager) throws IOException, SAXException {
- OMAParser omaParser = new OMAParser();
- return addSP(omaParser.parse(xml, OMAConstants.PPS_URN));
- }
-
- private static final List<String> FQDNPath = Arrays.asList(TAG_HomeSP, TAG_FQDN);
-
- /**
- * R1 *only* addSP method.
- *
- * @param homeSP
- * @throws IOException
- */
- public void addSP(HomeSP homeSP) throws IOException {
- if (!mEnabled) {
- throw new IOException("HS2.0 not enabled on this device");
- }
- if (mSPs.containsKey(homeSP.getFQDN())) {
- Log.d(OSUManager.TAG, "HS20 profile for " +
- homeSP.getFQDN() + " already exists");
- return;
- }
- Log.d(OSUManager.TAG, "Adding new HS20 profile for " + homeSP.getFQDN());
-
- OMAConstructed dummyRoot = new OMAConstructed(null, TAG_PerProviderSubscription, null);
- buildHomeSPTree(homeSP, dummyRoot, mSPs.size() + 1);
- try {
- addSP(dummyRoot);
- } catch (FileNotFoundException fnfe) {
- MOTree tree =
- MOTree.buildMgmtTree(OMAConstants.PPS_URN, OMAConstants.OMAVersion, dummyRoot);
- // No file to load a pre-build MO tree from, create a new one and save it.
- //MOTree tree = new MOTree(OMAConstants.PPS_URN, OMAConstants.OMAVersion, dummyRoot);
- writeMO(tree, mPpsFile);
- }
- mSPs.put(homeSP.getFQDN(), homeSP);
- }
-
- public HomeSP addSP(MOTree instanceTree) throws IOException {
- List<HomeSP> spList = buildSPs(instanceTree);
- if (spList.size() != 1) {
- throw new OMAException("Expected exactly one HomeSP, got " + spList.size());
- }
-
- HomeSP sp = spList.iterator().next();
- String fqdn = sp.getFQDN();
- if (mSPs.put(fqdn, sp) != null) {
- throw new OMAException("SP " + fqdn + " already exists");
- }
-
- OMAConstructed pps = (OMAConstructed) instanceTree.getRoot().
- getChild(TAG_PerProviderSubscription);
-
- try {
- addSP(pps);
- } catch (FileNotFoundException fnfe) {
- MOTree tree = new MOTree(instanceTree.getUrn(), instanceTree.getDtdRev(),
- instanceTree.getRoot());
- writeMO(tree, mPpsFile);
- }
-
- return sp;
- }
-
- /**
- * Add an SP sub-tree. mo must be PPS with an immediate instance child (e.g. Cred01) and an
- * optional UpdateIdentifier,
- *
- * @param mo The new MO
- * @throws IOException
- */
- private void addSP(OMANode mo) throws IOException {
- MOTree moTree;
- try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(mPpsFile))) {
- moTree = MOTree.unmarshal(in);
- moTree.getRoot().addChild(mo);
-
- /*
- OMAConstructed ppsRoot = (OMAConstructed)
- moTree.getRoot().addChild(TAG_PerProviderSubscription, "", null, null);
- for (OMANode child : mo.getChildren()) {
- ppsRoot.addChild(child);
- if (!child.isLeaf()) {
- moTree.getRoot().addChild(child);
- }
- else if (child.getName().equals(TAG_UpdateIdentifier)) {
- OMANode currentUD = moTree.getRoot().getChild(TAG_UpdateIdentifier);
- if (currentUD != null) {
- moTree.getRoot().replaceNode(currentUD, child);
- }
- else {
- moTree.getRoot().addChild(child);
- }
- }
- }
- */
- }
- writeMO(moTree, mPpsFile);
- }
-
- private static OMAConstructed findTargetTree(MOTree moTree, String fqdn) throws OMAException {
- OMANode pps = moTree.getRoot();
- for (OMANode node : pps.getChildren()) {
- OMANode instance = null;
- if (node.getName().equals(TAG_PerProviderSubscription)) {
- instance = getInstanceNode((OMAConstructed) node);
- } else if (!node.isLeaf()) {
- instance = node;
- }
- if (instance != null) {
- String nodeFqdn = getString(instance.getListValue(FQDNPath.iterator()));
- if (fqdn.equalsIgnoreCase(nodeFqdn)) {
- return (OMAConstructed) node;
- // targetTree is rooted at the PPS
- }
- }
- }
- return null;
- }
-
- private static OMAConstructed getInstanceNode(OMAConstructed root) throws OMAException {
- for (OMANode child : root.getChildren()) {
- if (!child.isLeaf()) {
- return (OMAConstructed) child;
- }
- }
- throw new OMAException("Cannot find instance node");
- }
-
- public static HomeSP modifySP(HomeSP homeSP, MOTree moTree, Collection<MOData> mods)
- throws OMAException {
-
- OMAConstructed ppsTree =
- (OMAConstructed) moTree.getRoot().getChildren().iterator().next();
- OMAConstructed instance = getInstanceNode(ppsTree);
-
- int ppsMods = 0;
- int updateIdentifier = homeSP.getUpdateIdentifier();
- for (MOData mod : mods) {
- LinkedList<String> tailPath =
- getTailPath(mod.getBaseURI(), TAG_PerProviderSubscription);
- OMAConstructed modRoot = mod.getMOTree().getRoot();
- // modRoot is the MgmtTree with the actual object as a direct child
- // (e.g. Credential)
-
- if (tailPath.getFirst().equals(TAG_UpdateIdentifier)) {
- updateIdentifier = getInteger(modRoot.getChildren().iterator().next());
- OMANode oldUdi = ppsTree.getChild(TAG_UpdateIdentifier);
- if (getInteger(oldUdi) != updateIdentifier) {
- ppsMods++;
- }
- if (oldUdi != null) {
- ppsTree.replaceNode(oldUdi, modRoot.getChild(TAG_UpdateIdentifier));
- } else {
- ppsTree.addChild(modRoot.getChild(TAG_UpdateIdentifier));
- }
- } else {
- tailPath.removeFirst(); // Drop the instance
- OMANode current = instance.getListValue(tailPath.iterator());
- if (current == null) {
- throw new OMAException("No previous node for " + tailPath + " in "
- + homeSP.getFQDN());
- }
- for (OMANode newNode : modRoot.getChildren()) {
- // newNode is something like Credential
- // current is the same existing node
- OMANode old = current.getParent().replaceNode(current, newNode);
- ppsMods++;
- }
- }
- }
-
- return ppsMods > 0 ? buildHomeSP(instance, updateIdentifier) : null;
- }
-
- public HomeSP modifySP(HomeSP homeSP, Collection<MOData> mods)
- throws IOException {
-
- Log.d(OSUManager.TAG, "modifying SP: " + mods);
- MOTree moTree;
- int ppsMods = 0;
- int updateIdentifier = 0;
- try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(mPpsFile))) {
- moTree = MOTree.unmarshal(in);
- // moTree is PPS/?/provider-data
-
- OMAConstructed targetTree = findTargetTree(moTree, homeSP.getFQDN());
- if (targetTree == null) {
- throw new IOException("Failed to find PPS tree for " + homeSP.getFQDN());
- }
- OMAConstructed instance = getInstanceNode(targetTree);
-
- for (MOData mod : mods) {
- LinkedList<String> tailPath =
- getTailPath(mod.getBaseURI(), TAG_PerProviderSubscription);
- OMAConstructed modRoot = mod.getMOTree().getRoot();
- // modRoot is the MgmtTree with the actual object as a direct child
- // (e.g. Credential)
-
- if (tailPath.getFirst().equals(TAG_UpdateIdentifier)) {
- updateIdentifier = getInteger(modRoot.getChildren().iterator().next());
- OMANode oldUdi = targetTree.getChild(TAG_UpdateIdentifier);
- if (getInteger(oldUdi) != updateIdentifier) {
- ppsMods++;
- }
- if (oldUdi != null) {
- targetTree.replaceNode(oldUdi, modRoot.getChild(TAG_UpdateIdentifier));
- } else {
- targetTree.addChild(modRoot.getChild(TAG_UpdateIdentifier));
- }
- } else {
- tailPath.removeFirst(); // Drop the instance
- OMANode current = instance.getListValue(tailPath.iterator());
- if (current == null) {
- throw new IOException("No previous node for " + tailPath + " in " +
- homeSP.getFQDN());
- }
- for (OMANode newNode : modRoot.getChildren()) {
- // newNode is something like Credential
- // current is the same existing node
- OMANode old = current.getParent().replaceNode(current, newNode);
- ppsMods++;
- }
- }
- }
- }
- writeMO(moTree, mPpsFile);
-
- if (ppsMods == 0) {
- return null; // HomeSP not modified.
- }
-
- // Return a new rebuilt HomeSP
- List<HomeSP> sps = buildSPs(moTree);
- if (sps != null) {
- for (HomeSP sp : sps) {
- if (sp.getFQDN().equals(homeSP.getFQDN())) {
- return sp;
- }
- }
- } else {
- throw new OMAException("Failed to build HomeSP");
- }
- return null;
- }
-
- private static LinkedList<String> getTailPath(String pathString, String rootName)
- throws OMAException {
- String[] path = pathString.split("/");
- int pathIndex;
- for (pathIndex = 0; pathIndex < path.length; pathIndex++) {
- if (path[pathIndex].equalsIgnoreCase(rootName)) {
- pathIndex++;
- break;
- }
- }
- if (pathIndex >= path.length) {
- throw new OMAException("Bad node-path: " + pathString);
- }
- LinkedList<String> tailPath = new LinkedList<>();
- while (pathIndex < path.length) {
- tailPath.add(path[pathIndex]);
- pathIndex++;
- }
- return tailPath;
- }
-
- public HomeSP getHomeSP(String fqdn) {
- return mSPs.get(fqdn);
- }
-
- public void removeSP(String fqdn) throws IOException {
- if (mSPs.remove(fqdn) == null) {
- Log.d(OSUManager.TAG, "No HS20 profile to delete for " + fqdn);
- return;
- }
-
- Log.d(OSUManager.TAG, "Deleting HS20 profile for " + fqdn);
-
- MOTree moTree;
- try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(mPpsFile))) {
- moTree = MOTree.unmarshal(in);
- OMAConstructed tbd = findTargetTree(moTree, fqdn);
- if (tbd == null) {
- throw new IOException("Node " + fqdn + " doesn't exist in MO tree");
- }
- OMAConstructed pps = moTree.getRoot();
- OMANode removed = pps.removeNode("?", tbd);
- if (removed == null) {
- throw new IOException("Failed to remove " + fqdn + " out of MO tree");
- }
- }
- writeMO(moTree, mPpsFile);
- }
-
- public MOTree getMOTree(HomeSP homeSP) throws IOException {
- try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(mPpsFile))) {
- MOTree moTree = MOTree.unmarshal(in);
- OMAConstructed target = findTargetTree(moTree, homeSP.getFQDN());
- if (target == null) {
- throw new IOException("Can't find " + homeSP.getFQDN() + " in MO tree");
- }
- return MOTree.buildMgmtTree(OMAConstants.PPS_URN, OMAConstants.OMAVersion, target);
- }
- }
-
- private static void writeMO(MOTree moTree, File f) throws IOException {
- try (BufferedOutputStream out =
- new BufferedOutputStream(new FileOutputStream(f, false))) {
- moTree.marshal(out);
- out.flush();
- }
- }
-
- private static String fqdnList(Collection<HomeSP> sps) {
- StringBuilder sb = new StringBuilder();
- boolean first = true;
- for (HomeSP sp : sps) {
- if (first) {
- first = false;
- } else {
- sb.append(", ");
- }
- sb.append(sp.getFQDN());
- }
- return sb.toString();
- }
-
- private static OMANode buildHomeSPTree(HomeSP homeSP, OMAConstructed root, int instanceID)
- throws IOException {
- OMANode providerSubNode = root.addChild(getInstanceString(instanceID),
- null, null, null);
-
- // The HomeSP:
- OMANode homeSpNode = providerSubNode.addChild(TAG_HomeSP, null, null, null);
- if (!homeSP.getSSIDs().isEmpty()) {
- OMAConstructed nwkIDNode =
- (OMAConstructed) homeSpNode.addChild(TAG_NetworkID, null, null, null);
- int instance = 0;
- for (Map.Entry<String, Long> entry : homeSP.getSSIDs().entrySet()) {
- OMAConstructed inode =
- (OMAConstructed) nwkIDNode
- .addChild(getInstanceString(instance++), null, null, null);
- inode.addChild(TAG_SSID, null, entry.getKey(), null);
- if (entry.getValue() != null) {
- inode.addChild(TAG_HESSID, null,
- String.format("%012x", entry.getValue()), null);
- }
- }
- }
-
- homeSpNode.addChild(TAG_FriendlyName, null, homeSP.getFriendlyName(), null);
-
- if (homeSP.getIconURL() != null) {
- homeSpNode.addChild(TAG_IconURL, null, homeSP.getIconURL(), null);
- }
-
- homeSpNode.addChild(TAG_FQDN, null, homeSP.getFQDN(), null);
-
- if (!homeSP.getMatchAllOIs().isEmpty() || !homeSP.getMatchAnyOIs().isEmpty()) {
- OMAConstructed homeOIList =
- (OMAConstructed) homeSpNode.addChild(TAG_HomeOIList, null, null, null);
-
- int instance = 0;
- for (Long oi : homeSP.getMatchAllOIs()) {
- OMAConstructed inode =
- (OMAConstructed) homeOIList.addChild(getInstanceString(instance++),
- null, null, null);
- inode.addChild(TAG_HomeOI, null, String.format("%x", oi), null);
- inode.addChild(TAG_HomeOIRequired, null, "TRUE", null);
- }
- for (Long oi : homeSP.getMatchAnyOIs()) {
- OMAConstructed inode =
- (OMAConstructed) homeOIList.addChild(getInstanceString(instance++),
- null, null, null);
- inode.addChild(TAG_HomeOI, null, String.format("%x", oi), null);
- inode.addChild(TAG_HomeOIRequired, null, "FALSE", null);
- }
- }
-
- if (!homeSP.getOtherHomePartners().isEmpty()) {
- OMAConstructed otherPartners =
- (OMAConstructed) homeSpNode.addChild(TAG_OtherHomePartners, null, null, null);
- int instance = 0;
- for (String fqdn : homeSP.getOtherHomePartners()) {
- OMAConstructed inode =
- (OMAConstructed) otherPartners.addChild(getInstanceString(instance++),
- null, null, null);
- inode.addChild(TAG_FQDN, null, fqdn, null);
- }
- }
-
- if (!homeSP.getRoamingConsortiums().isEmpty()) {
- homeSpNode.addChild(TAG_RoamingConsortiumOI, null,
- getRCList(homeSP.getRoamingConsortiums()), null);
- }
-
- // The Credential:
- OMANode credentialNode = providerSubNode.addChild(TAG_Credential, null, null, null);
- Credential cred = homeSP.getCredential();
- EAPMethod method = cred.getEAPMethod();
-
- if (cred.getCtime() > 0) {
- credentialNode.addChild(TAG_CreationDate,
- null, DTFormat.format(new Date(cred.getCtime())), null);
- }
- if (cred.getExpTime() > 0) {
- credentialNode.addChild(TAG_ExpirationDate,
- null, DTFormat.format(new Date(cred.getExpTime())), null);
- }
-
- if (method.getEAPMethodID() == EAP.EAPMethodID.EAP_SIM
- || method.getEAPMethodID() == EAP.EAPMethodID.EAP_AKA
- || method.getEAPMethodID() == EAP.EAPMethodID.EAP_AKAPrim) {
-
- OMANode simNode = credentialNode.addChild(TAG_SIM, null, null, null);
- simNode.addChild(TAG_IMSI, null, cred.getImsi().toString(), null);
- simNode.addChild(TAG_EAPType, null,
- Integer.toString(EAP.mapEAPMethod(method.getEAPMethodID())), null);
-
- } else if (method.getEAPMethodID() == EAP.EAPMethodID.EAP_TTLS) {
-
- OMANode unpNode = credentialNode.addChild(TAG_UsernamePassword, null, null, null);
- unpNode.addChild(TAG_Username, null, cred.getUserName(), null);
- unpNode.addChild(TAG_Password, null,
- Base64.encodeToString(cred.getPassword().getBytes(StandardCharsets.UTF_8),
- Base64.DEFAULT), null);
- OMANode eapNode = unpNode.addChild(TAG_EAPMethod, null, null, null);
- eapNode.addChild(TAG_EAPType, null,
- Integer.toString(EAP.mapEAPMethod(method.getEAPMethodID())), null);
- eapNode.addChild(TAG_InnerMethod, null,
- ((NonEAPInnerAuth) method.getAuthParam()).getOMAtype(), null);
-
- } else if (method.getEAPMethodID() == EAP.EAPMethodID.EAP_TLS) {
-
- OMANode certNode = credentialNode.addChild(TAG_DigitalCertificate, null, null, null);
- certNode.addChild(TAG_CertificateType, null, Credential.CertTypeX509, null);
- certNode.addChild(TAG_CertSHA256Fingerprint, null,
- Utils.toHex(cred.getFingerPrint()), null);
-
- } else {
- throw new OMAException("Invalid credential on " + homeSP.getFQDN());
- }
-
- credentialNode.addChild(TAG_Realm, null, cred.getRealm(), null);
-
- // !!! Note: This node defines CRL checking through OSCP, I suspect we won't be able
- // to do that so it is commented out:
- //credentialNode.addChild(TAG_CheckAAAServerCertStatus, null, "TRUE", null);
- return providerSubNode;
- }
-
- private static String getInstanceString(int instance) {
- return "r1i" + instance;
- }
-
- private static String getRCList(Collection<Long> rcs) {
- StringBuilder builder = new StringBuilder();
- boolean first = true;
- for (Long roamingConsortium : rcs) {
- if (first) {
- first = false;
- } else {
- builder.append(',');
- }
- builder.append(String.format("%x", roamingConsortium));
- }
- return builder.toString();
- }
-
- public static List<HomeSP> buildSPs(MOTree moTree) throws OMAException {
- OMAConstructed spList;
- List<HomeSP> homeSPs = new ArrayList<>();
- if (moTree.getRoot().getName().equals(TAG_PerProviderSubscription)) {
- // The old PPS file was rooted at PPS instead of MgmtTree to conserve space
- spList = moTree.getRoot();
-
- if (spList == null) {
- return homeSPs;
- }
-
- for (OMANode node : spList.getChildren()) {
- if (!node.isLeaf()) {
- homeSPs.add(buildHomeSP(node, 0));
- }
- }
- } else {
- for (OMANode ppsRoot : moTree.getRoot().getChildren()) {
- if (ppsRoot.getName().equals(TAG_PerProviderSubscription)) {
- Integer updateIdentifier = null;
- OMANode instance = null;
- for (OMANode child : ppsRoot.getChildren()) {
- if (child.getName().equals(TAG_UpdateIdentifier)) {
- updateIdentifier = getInteger(child);
- } else if (!child.isLeaf()) {
- instance = child;
- }
- }
- if (instance == null) {
- throw new OMAException("PPS node missing instance node");
- }
- homeSPs.add(buildHomeSP(instance,
- updateIdentifier != null ? updateIdentifier : 0));
- }
- }
- }
-
- return homeSPs;
- }
-
- private static HomeSP buildHomeSP(OMANode ppsRoot, int updateIdentifier) throws OMAException {
- OMANode spRoot = ppsRoot.getChild(TAG_HomeSP);
-
- String fqdn = spRoot.getScalarValue(Arrays.asList(TAG_FQDN).iterator());
- String friendlyName = spRoot.getScalarValue(Arrays.asList(TAG_FriendlyName).iterator());
- String iconURL = spRoot.getScalarValue(Arrays.asList(TAG_IconURL).iterator());
-
- HashSet<Long> roamingConsortiums = new HashSet<>();
- String oiString = spRoot.getScalarValue(Arrays.asList(TAG_RoamingConsortiumOI).iterator());
- if (oiString != null) {
- for (String oi : oiString.split(",")) {
- roamingConsortiums.add(Long.parseLong(oi.trim(), 16));
- }
- }
-
- Map<String, Long> ssids = new HashMap<>();
-
- OMANode ssidListNode = spRoot.getListValue(Arrays.asList(TAG_NetworkID).iterator());
- if (ssidListNode != null) {
- for (OMANode ssidRoot : ssidListNode.getChildren()) {
- OMANode hessidNode = ssidRoot.getChild(TAG_HESSID);
- ssids.put(ssidRoot.getChild(TAG_SSID).getValue(), getMac(hessidNode));
- }
- }
-
- Set<Long> matchAnyOIs = new HashSet<>();
- List<Long> matchAllOIs = new ArrayList<>();
- OMANode homeOIListNode = spRoot.getListValue(Arrays.asList(TAG_HomeOIList).iterator());
- if (homeOIListNode != null) {
- for (OMANode homeOIRoot : homeOIListNode.getChildren()) {
- String homeOI = homeOIRoot.getChild(TAG_HomeOI).getValue();
- if (Boolean.parseBoolean(homeOIRoot.getChild(TAG_HomeOIRequired).getValue())) {
- matchAllOIs.add(Long.parseLong(homeOI, 16));
- } else {
- matchAnyOIs.add(Long.parseLong(homeOI, 16));
- }
- }
- }
-
- Set<String> otherHomePartners = new HashSet<>();
- OMANode otherListNode =
- spRoot.getListValue(Arrays.asList(TAG_OtherHomePartners).iterator());
- if (otherListNode != null) {
- for (OMANode fqdnNode : otherListNode.getChildren()) {
- otherHomePartners.add(fqdnNode.getChild(TAG_FQDN).getValue());
- }
- }
-
- Credential credential = buildCredential(ppsRoot.getChild(TAG_Credential));
-
- OMANode policyNode = ppsRoot.getChild(TAG_Policy);
- Policy policy = policyNode != null ? new Policy(policyNode) : null;
-
- Map<String, String> aaaTrustRoots;
- OMANode aaaRootNode = ppsRoot.getChild(TAG_AAAServerTrustRoot);
- if (aaaRootNode == null) {
- aaaTrustRoots = null;
- } else {
- aaaTrustRoots = new HashMap<>(aaaRootNode.getChildren().size());
- for (OMANode child : aaaRootNode.getChildren()) {
- aaaTrustRoots.put(getString(child, TAG_CertURL),
- getString(child, TAG_CertSHA256Fingerprint));
- }
- }
-
- OMANode updateNode = ppsRoot.getChild(TAG_SubscriptionUpdate);
- UpdateInfo subscriptionUpdate = updateNode != null ? new UpdateInfo(updateNode) : null;
- OMANode subNode = ppsRoot.getChild(TAG_SubscriptionParameters);
- SubscriptionParameters subscriptionParameters = subNode != null ?
- new SubscriptionParameters(subNode) : null;
-
- return new HomeSP(ssids, fqdn, roamingConsortiums, otherHomePartners,
- matchAnyOIs, matchAllOIs, friendlyName, iconURL, credential,
- policy, getInteger(ppsRoot.getChild(TAG_CredentialPriority), 0),
- aaaTrustRoots, subscriptionUpdate, subscriptionParameters, updateIdentifier);
- }
-
- private static Credential buildCredential(OMANode credNode) throws OMAException {
- long ctime = getTime(credNode.getChild(TAG_CreationDate));
- long expTime = getTime(credNode.getChild(TAG_ExpirationDate));
- String realm = getString(credNode.getChild(TAG_Realm));
- boolean checkAAACert = getBoolean(credNode.getChild(TAG_CheckAAAServerCertStatus));
-
- OMANode unNode = credNode.getChild(TAG_UsernamePassword);
- OMANode certNode = credNode.getChild(TAG_DigitalCertificate);
- OMANode simNode = credNode.getChild(TAG_SIM);
-
- int alternatives = 0;
- alternatives += unNode != null ? 1 : 0;
- alternatives += certNode != null ? 1 : 0;
- alternatives += simNode != null ? 1 : 0;
- if (alternatives != 1) {
- throw new OMAException("Expected exactly one credential type, got " + alternatives);
- }
-
- if (unNode != null) {
- String userName = getString(unNode.getChild(TAG_Username));
- String password = getString(unNode.getChild(TAG_Password));
- boolean machineManaged = getBoolean(unNode.getChild(TAG_MachineManaged));
- String softTokenApp = getString(unNode.getChild(TAG_SoftTokenApp));
- boolean ableToShare = getBoolean(unNode.getChild(TAG_AbleToShare));
-
- OMANode eapMethodNode = unNode.getChild(TAG_EAPMethod);
- int eapID = getInteger(eapMethodNode.getChild(TAG_EAPType));
-
- EAP.EAPMethodID eapMethodID = EAP.mapEAPMethod(eapID);
- if (eapMethodID == null) {
- throw new OMAException("Unknown EAP method: " + eapID);
- }
-
- Long vid = getOptionalInteger(eapMethodNode.getChild(TAG_VendorId));
- Long vtype = getOptionalInteger(eapMethodNode.getChild(TAG_VendorType));
- Long innerEAPType = getOptionalInteger(eapMethodNode.getChild(TAG_InnerEAPType));
- EAP.EAPMethodID innerEAPMethod = null;
- if (innerEAPType != null) {
- innerEAPMethod = EAP.mapEAPMethod(innerEAPType.intValue());
- if (innerEAPMethod == null) {
- throw new OMAException("Bad inner EAP method: " + innerEAPType);
- }
- }
-
- Long innerVid = getOptionalInteger(eapMethodNode.getChild(TAG_InnerVendorID));
- Long innerVtype = getOptionalInteger(eapMethodNode.getChild(TAG_InnerVendorType));
- String innerNonEAPMethod = getString(eapMethodNode.getChild(TAG_InnerMethod));
-
- EAPMethod eapMethod;
- if (innerEAPMethod != null) {
- eapMethod = new EAPMethod(eapMethodID, new InnerAuthEAP(innerEAPMethod));
- } else if (vid != null) {
- eapMethod = new EAPMethod(eapMethodID,
- new ExpandedEAPMethod(EAP.AuthInfoID.ExpandedEAPMethod,
- vid.intValue(), vtype));
- } else if (innerVid != null) {
- eapMethod =
- new EAPMethod(eapMethodID, new ExpandedEAPMethod(EAP.AuthInfoID
- .ExpandedInnerEAPMethod, innerVid.intValue(), innerVtype));
- } else if (innerNonEAPMethod != null) {
- eapMethod = new EAPMethod(eapMethodID, new NonEAPInnerAuth(innerNonEAPMethod));
- } else {
- throw new OMAException("Incomplete set of EAP parameters");
- }
-
- return new Credential(ctime, expTime, realm, checkAAACert, eapMethod, userName,
- password, machineManaged, softTokenApp, ableToShare);
- }
- if (certNode != null) {
- try {
- String certTypeString = getString(certNode.getChild(TAG_CertificateType));
- byte[] fingerPrint = getOctets(certNode.getChild(TAG_CertSHA256Fingerprint));
-
- EAPMethod eapMethod = new EAPMethod(EAP.EAPMethodID.EAP_TLS, null);
-
- return new Credential(ctime, expTime, realm, checkAAACert, eapMethod,
- Credential.mapCertType(certTypeString), fingerPrint);
- } catch (NumberFormatException nfe) {
- throw new OMAException("Bad hex string: " + nfe.toString());
- }
- }
- if (simNode != null) {
- try {
- IMSIParameter imsi = new IMSIParameter(getString(simNode.getChild(TAG_IMSI)));
-
- EAPMethod eapMethod =
- new EAPMethod(EAP.mapEAPMethod(getInteger(simNode.getChild(TAG_EAPType))),
- null);
-
- return new Credential(ctime, expTime, realm, checkAAACert, eapMethod, imsi);
- } catch (IOException ioe) {
- throw new OMAException("Failed to parse IMSI: " + ioe);
- }
- }
- throw new OMAException("Missing credential parameters");
- }
-
- public static OMANode getChild(OMANode node, String key) throws OMAException {
- OMANode child = node.getChild(key);
- if (child == null) {
- throw new OMAException("No such node: " + key);
- }
- return child;
- }
-
- public static String getString(OMANode node, String key) throws OMAException {
- OMANode child = node.getChild(key);
- if (child == null) {
- throw new OMAException("Missing value for " + key);
- } else if (!child.isLeaf()) {
- throw new OMAException(key + " is not a leaf node");
- }
- return child.getValue();
- }
-
- public static long getLong(OMANode node, String key, Long dflt) throws OMAException {
- OMANode child = node.getChild(key);
- if (child == null) {
- if (dflt != null) {
- return dflt;
- } else {
- throw new OMAException("Missing value for " + key);
- }
- } else {
- if (!child.isLeaf()) {
- throw new OMAException(key + " is not a leaf node");
- }
- String value = child.getValue();
- try {
- long result = Long.parseLong(value);
- if (result < 0) {
- throw new OMAException("Negative value for " + key);
- }
- return result;
- } catch (NumberFormatException nfe) {
- throw new OMAException("Value for " + key + " is non-numeric: " + value);
- }
- }
- }
-
- public static <T> T getSelection(OMANode node, String key) throws OMAException {
- OMANode child = node.getChild(key);
- if (child == null) {
- throw new OMAException("Missing value for " + key);
- } else if (!child.isLeaf()) {
- throw new OMAException(key + " is not a leaf node");
- }
- return getSelection(key, child.getValue());
- }
-
- public static <T> T getSelection(String key, String value) throws OMAException {
- if (value == null) {
- throw new OMAException("No value for " + key);
- }
- Map<String, Object> kvp = sSelectionMap.get(key);
- T result = (T) kvp.get(value.toLowerCase());
- if (result == null) {
- throw new OMAException("Invalid value '" + value + "' for " + key);
- }
- return result;
- }
-
- private static boolean getBoolean(OMANode boolNode) {
- return boolNode != null && Boolean.parseBoolean(boolNode.getValue());
- }
-
- public static String getString(OMANode stringNode) {
- return stringNode != null ? stringNode.getValue() : null;
- }
-
- private static int getInteger(OMANode intNode, int dflt) throws OMAException {
- if (intNode == null) {
- return dflt;
- }
- return getInteger(intNode);
- }
-
- private static int getInteger(OMANode intNode) throws OMAException {
- if (intNode == null) {
- throw new OMAException("Missing integer value");
- }
- try {
- return Integer.parseInt(intNode.getValue());
- } catch (NumberFormatException nfe) {
- throw new OMAException("Invalid integer: " + intNode.getValue());
- }
- }
-
- private static Long getMac(OMANode macNode) throws OMAException {
- if (macNode == null) {
- return null;
- }
- try {
- return Long.parseLong(macNode.getValue(), 16);
- } catch (NumberFormatException nfe) {
- throw new OMAException("Invalid MAC: " + macNode.getValue());
- }
- }
-
- private static Long getOptionalInteger(OMANode intNode) throws OMAException {
- if (intNode == null) {
- return null;
- }
- try {
- return Long.parseLong(intNode.getValue());
- } catch (NumberFormatException nfe) {
- throw new OMAException("Invalid integer: " + intNode.getValue());
- }
- }
-
- public static long getTime(OMANode timeNode) throws OMAException {
- if (timeNode == null) {
- return Utils.UNSET_TIME;
- }
- String timeText = timeNode.getValue();
- try {
- Date date = DTFormat.parse(timeText);
- return date.getTime();
- } catch (ParseException pe) {
- throw new OMAException("Badly formatted time: " + timeText);
- }
- }
-
- private static byte[] getOctets(OMANode octetNode) throws OMAException {
- if (octetNode == null) {
- throw new OMAException("Missing byte value");
- }
- return Utils.hexToBytes(octetNode.getValue());
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/omadm/MOTree.java b/packages/Osu/src/com/android/hotspot2/omadm/MOTree.java
deleted file mode 100644
index 0c5ce4065239..000000000000
--- a/packages/Osu/src/com/android/hotspot2/omadm/MOTree.java
+++ /dev/null
@@ -1,269 +0,0 @@
-package com.android.hotspot2.omadm;
-
-import org.xml.sax.SAXException;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-public class MOTree {
- public static final String MgmtTreeTag = "MgmtTree";
-
- public static final String NodeTag = "Node";
- public static final String NodeNameTag = "NodeName";
- public static final String PathTag = "Path";
- public static final String ValueTag = "Value";
- public static final String RTPropTag = "RTProperties";
- public static final String TypeTag = "Type";
- public static final String DDFNameTag = "DDFName";
-
- private final String mUrn;
- private final String mDtdRev;
- private final OMAConstructed mRoot;
-
- public MOTree(XMLNode node, String urn) throws IOException, SAXException {
- Iterator<XMLNode> children = node.getChildren().iterator();
-
- String dtdRev = null;
-
- while (children.hasNext()) {
- XMLNode child = children.next();
- if (child.getTag().equals(OMAConstants.SyncMLVersionTag)) {
- dtdRev = child.getText();
- children.remove();
- break;
- }
- }
-
- mUrn = urn;
- mDtdRev = dtdRev;
-
- mRoot = new MgmtTreeRoot(node, dtdRev);
-
- for (XMLNode child : node.getChildren()) {
- buildNode(mRoot, child);
- }
- }
-
- public MOTree(String urn, String rev, OMAConstructed root) throws IOException {
- mUrn = urn;
- mDtdRev = rev;
- mRoot = root;
- }
-
- public static MOTree buildMgmtTree(String urn, String rev, OMAConstructed root)
- throws IOException {
- OMAConstructed realRoot;
- switch (urn) {
- case OMAConstants.PPS_URN:
- case OMAConstants.DevInfoURN:
- case OMAConstants.DevDetailURN:
- case OMAConstants.DevDetailXURN:
- realRoot = new MgmtTreeRoot(OMAConstants.OMAVersion);
- realRoot.addChild(root);
- return new MOTree(urn, rev, realRoot);
- default:
- return new MOTree(urn, rev, root);
- }
- }
-
- public static boolean hasMgmtTreeTag(String text) {
- for (int n = 0; n < text.length(); n++) {
- char ch = text.charAt(n);
- if (ch > ' ') {
- return text.regionMatches(true, n, '<' + MgmtTreeTag + '>',
- 0, MgmtTreeTag.length() + 2);
- }
- }
- return false;
- }
-
- private static class NodeData {
- private final String mName;
- private String mPath;
- private String mValue;
-
- private NodeData(String name) {
- mName = name;
- }
-
- private void setPath(String path) {
- mPath = path;
- }
-
- private void setValue(String value) {
- mValue = value;
- }
-
- public String getName() {
- return mName;
- }
-
- public String getPath() {
- return mPath;
- }
-
- public String getValue() {
- return mValue;
- }
- }
-
- private static void buildNode(OMANode parent, XMLNode node) throws IOException {
- if (!node.getTag().equals(NodeTag))
- throw new IOException("Node is a '" + node.getTag() + "' instead of a 'Node'");
-
- Map<String, XMLNode> checkMap = new HashMap<>(3);
- String context = null;
- List<NodeData> values = new ArrayList<>();
- List<XMLNode> children = new ArrayList<>();
-
- NodeData curValue = null;
-
- for (XMLNode child : node.getChildren()) {
- XMLNode old = checkMap.put(child.getTag(), child);
-
- switch (child.getTag()) {
- case NodeNameTag:
- if (curValue != null)
- throw new IOException(NodeNameTag + " not expected");
- curValue = new NodeData(child.getText());
-
- break;
- case PathTag:
- if (curValue == null || curValue.getPath() != null)
- throw new IOException(PathTag + " not expected");
- curValue.setPath(child.getText());
-
- break;
- case ValueTag:
- if (!children.isEmpty())
- throw new IOException(ValueTag + " in constructed node");
- if (curValue == null || curValue.getValue() != null)
- throw new IOException(ValueTag + " not expected");
- curValue.setValue(child.getText());
- values.add(curValue);
- curValue = null;
-
- break;
- case RTPropTag:
- if (old != null)
- throw new IOException("Duplicate " + RTPropTag);
- XMLNode typeNode = getNextNode(child, TypeTag);
- XMLNode ddfName = getNextNode(typeNode, DDFNameTag);
- context = ddfName.getText();
- if (context == null)
- throw new IOException("No text in " + DDFNameTag);
-
- break;
- case NodeTag:
- if (!values.isEmpty())
- throw new IOException("Scalar node " + node.getText() + " has Node child");
- children.add(child);
-
- break;
- }
- }
-
- if (values.isEmpty()) {
- if (curValue == null)
- throw new IOException("Missing name");
-
- OMANode subNode = parent.addChild(curValue.getName(),
- context, null, curValue.getPath());
-
- for (XMLNode child : children) {
- buildNode(subNode, child);
- }
- } else {
- if (!children.isEmpty())
- throw new IOException("Got both sub nodes and value(s)");
-
- for (NodeData nodeData : values) {
- parent.addChild(nodeData.getName(), context,
- nodeData.getValue(), nodeData.getPath());
- }
- }
- }
-
- private static XMLNode getNextNode(XMLNode node, String tag) throws IOException {
- if (node == null)
- throw new IOException("No node for " + tag);
- if (node.getChildren().size() != 1)
- throw new IOException("Expected " + node.getTag() + " to have exactly one child");
- XMLNode child = node.getChildren().iterator().next();
- if (!child.getTag().equals(tag))
- throw new IOException("Expected " + node.getTag() + " to have child '" + tag +
- "' instead of '" + child.getTag() + "'");
- return child;
- }
-
- public String getUrn() {
- return mUrn;
- }
-
- public String getDtdRev() {
- return mDtdRev;
- }
-
- public OMAConstructed getRoot() {
- return mRoot;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("MO Tree v").append(mDtdRev).append(", urn ").append(mUrn).append(")\n");
- sb.append(mRoot);
-
- return sb.toString();
- }
-
- public void marshal(OutputStream out) throws IOException {
- out.write("tree ".getBytes(StandardCharsets.UTF_8));
- OMAConstants.serializeString(mDtdRev, out);
- out.write(String.format("(%s)\n", mUrn).getBytes(StandardCharsets.UTF_8));
- mRoot.marshal(out, 0);
- }
-
- public static MOTree unmarshal(InputStream in) throws IOException {
- boolean strip = true;
- StringBuilder tree = new StringBuilder();
- for (; ; ) {
- int octet = in.read();
- if (octet < 0) {
- return null;
- } else if (octet > ' ') {
- tree.append((char) octet);
- strip = false;
- } else if (!strip) {
- break;
- }
- }
- if (!tree.toString().equals("tree")) {
- throw new IOException("Not a tree: " + tree);
- }
-
- String version = OMAConstants.deserializeString(in);
- int next = in.read();
- if (next != '(') {
- throw new IOException("Expected URN in tree definition");
- }
- String urn = OMAConstants.readURN(in);
-
- OMAConstructed root = OMANode.unmarshal(in);
-
- return new MOTree(urn, version, root);
- }
-
- public String toXml() {
- StringBuilder sb = new StringBuilder();
- mRoot.toXml(sb);
- return sb.toString();
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/omadm/MgmtTreeRoot.java b/packages/Osu/src/com/android/hotspot2/omadm/MgmtTreeRoot.java
deleted file mode 100644
index 9416140e9e18..000000000000
--- a/packages/Osu/src/com/android/hotspot2/omadm/MgmtTreeRoot.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.android.hotspot2.omadm;
-
-import java.util.Map;
-
-public class MgmtTreeRoot extends OMAConstructed {
- private final String mDtdRev;
-
- public MgmtTreeRoot(XMLNode node, String dtdRev) {
- super(null, MOTree.MgmtTreeTag, null, new MultiValueMap<OMANode>(),
- node.getTextualAttributes());
- mDtdRev = dtdRev;
- }
-
- public MgmtTreeRoot(String dtdRev) {
- super(null, MOTree.MgmtTreeTag, null, "xmlns", OMAConstants.SyncML);
- mDtdRev = dtdRev;
- }
-
- @Override
- public void toXml(StringBuilder sb) {
- sb.append('<').append(MOTree.MgmtTreeTag);
- if (getAttributes() != null && !getAttributes().isEmpty()) {
- for (Map.Entry<String, String> avp : getAttributes().entrySet()) {
- sb.append(' ').append(avp.getKey()).append("=\"")
- .append(avp.getValue()).append('"');
- }
- }
- sb.append(">\n");
-
- sb.append('<').append(OMAConstants.SyncMLVersionTag).append('>').append(mDtdRev)
- .append("</").append(OMAConstants.SyncMLVersionTag).append(">\n");
- for (OMANode child : getChildren()) {
- child.toXml(sb);
- }
- sb.append("</").append(MOTree.MgmtTreeTag).append(">\n");
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/omadm/MultiValueMap.java b/packages/Osu/src/com/android/hotspot2/omadm/MultiValueMap.java
deleted file mode 100644
index ead0dbc79d6a..000000000000
--- a/packages/Osu/src/com/android/hotspot2/omadm/MultiValueMap.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package com.android.hotspot2.omadm;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-public class MultiValueMap<T> {
- private final Map<String, ArrayList<T>> mMap = new LinkedHashMap<>();
-
- public void put(String key, T value) {
- key = key.toLowerCase();
- ArrayList<T> values = mMap.get(key);
- if (values == null) {
- values = new ArrayList<>();
- mMap.put(key, values);
- }
- values.add(value);
- }
-
- public T get(String key) {
- key = key.toLowerCase();
- List<T> values = mMap.get(key);
- if (values == null) {
- return null;
- } else if (values.size() == 1) {
- return values.get(0);
- } else {
- throw new IllegalArgumentException("Cannot do get on multi-value");
- }
- }
-
- public T replace(String key, T oldValue, T newValue) {
- key = key.toLowerCase();
- List<T> values = mMap.get(key);
- if (values == null) {
- return null;
- }
-
- for (int n = 0; n < values.size(); n++) {
- T value = values.get(n);
- if (value == oldValue) {
- values.set(n, newValue);
- return value;
- }
- }
- return null;
- }
-
- public T remove(String key, T value) {
- key = key.toLowerCase();
- List<T> values = mMap.get(key);
- if (values == null) {
- return null;
- }
-
- T result = null;
- Iterator<T> valueIterator = values.iterator();
- while (valueIterator.hasNext()) {
- if (valueIterator.next() == value) {
- valueIterator.remove();
- result = value;
- break;
- }
- }
- if (values.isEmpty()) {
- mMap.remove(key);
- }
- return result;
- }
-
- public T remove(T value) {
- T result = null;
- Iterator<Map.Entry<String, ArrayList<T>>> iterator = mMap.entrySet().iterator();
- while (iterator.hasNext()) {
- ArrayList<T> values = iterator.next().getValue();
- Iterator<T> valueIterator = values.iterator();
- while (valueIterator.hasNext()) {
- if (valueIterator.next() == value) {
- valueIterator.remove();
- result = value;
- break;
- }
- }
- if (result != null) {
- if (values.isEmpty()) {
- iterator.remove();
- }
- break;
- }
- }
- return result;
- }
-
- public Collection<T> values() {
- List<T> allValues = new ArrayList<>(mMap.size());
- for (List<T> values : mMap.values()) {
- for (T value : values) {
- allValues.add(value);
- }
- }
- return allValues;
- }
-
- public T getSingletonValue() {
- if (mMap.size() != 1) {
- throw new IllegalArgumentException("Map is not a single entry map");
- }
- List<T> values = mMap.values().iterator().next();
- if (values.size() != 1) {
- throw new IllegalArgumentException("Map is not a single entry map");
- }
- return values.iterator().next();
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/omadm/NodeAttribute.java b/packages/Osu/src/com/android/hotspot2/omadm/NodeAttribute.java
deleted file mode 100644
index e4a08b37ae8a..000000000000
--- a/packages/Osu/src/com/android/hotspot2/omadm/NodeAttribute.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.android.hotspot2.omadm;
-
-public class NodeAttribute {
- private final String mName;
- private final String mType;
- private final String mValue;
-
- public NodeAttribute(String name, String type, String value) {
- mName = name;
- mType = type;
- mValue = value;
- }
-
- public String getName() {
- return mName;
- }
-
- public String getValue() {
- return mValue;
- }
-
- public String getType() {
- return mType;
- }
-
- @Override
- public String toString() {
- return String.format("%s (%s) = '%s'", mName, mType, mValue);
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/omadm/OMAConstants.java b/packages/Osu/src/com/android/hotspot2/omadm/OMAConstants.java
deleted file mode 100644
index 92d8ed7e991b..000000000000
--- a/packages/Osu/src/com/android/hotspot2/omadm/OMAConstants.java
+++ /dev/null
@@ -1,158 +0,0 @@
-package com.android.hotspot2.omadm;
-
-import com.android.hotspot2.osu.OSUError;
-import com.android.hotspot2.osu.OSUStatus;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.EnumMap;
-import java.util.HashMap;
-import java.util.Map;
-
-public class OMAConstants {
- private OMAConstants() {
- }
-
- public static final String MOVersion = "1.0";
- public static final String PPS_URN = "urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0";
- public static final String DevInfoURN = "urn:oma:mo:oma-dm-devinfo:1.0";
- public static final String DevDetailURN = "urn:oma:mo:oma-dm-devdetail:1.0";
- public static final String DevDetailXURN = "urn:wfa:mo-ext:hotspot2dot0-devdetail-ext:1.0";
-
- public static final String[] SupportedMO_URNs = {
- PPS_URN, DevInfoURN, DevDetailURN, DevDetailXURN
- };
-
- public static final String SppMOAttribute = "spp:moURN";
- public static final String TAG_PostDevData = "spp:sppPostDevData";
- public static final String TAG_SupportedVersions = "spp:supportedSPPVersions";
- public static final String TAG_SupportedMOs = "spp:supportedMOList";
- public static final String TAG_UpdateResponse = "spp:sppUpdateResponse";
- public static final String TAG_MOContainer = "spp:moContainer";
- public static final String TAG_Version = "spp:sppVersion";
-
- public static final String TAG_SessionID = "spp:sessionID";
- public static final String TAG_Status = "spp:sppStatus";
- public static final String TAG_Error = "spp:sppError";
-
- public static final String SyncMLVersionTag = "VerDTD";
- public static final String OMAVersion = "1.2";
- public static final String SyncML = "syncml:dmddf1.2";
-
- private static final byte[] INDENT = new byte[1024];
-
- private static final Map<OSUStatus, String> sStatusStrings = new EnumMap<>(OSUStatus.class);
- private static final Map<String, OSUStatus> sStatusEnums = new HashMap<>();
- private static final Map<OSUError, String> sErrorStrings = new EnumMap<>(OSUError.class);
- private static final Map<String, OSUError> sErrorEnums = new HashMap<>();
-
- static {
- sStatusStrings.put(OSUStatus.OK, "OK");
- sStatusStrings.put(OSUStatus.ProvComplete,
- "Provisioning complete, request sppUpdateResponse");
- sStatusStrings.put(OSUStatus.RemediationComplete,
- "Remediation complete, request sppUpdateResponse");
- sStatusStrings.put(OSUStatus.UpdateComplete, "Update complete, request sppUpdateResponse");
- sStatusStrings.put(OSUStatus.ExchangeComplete, "Exchange complete, release TLS connection");
- sStatusStrings.put(OSUStatus.Unknown, "No update available at this time");
- sStatusStrings.put(OSUStatus.Error, "Error occurred");
-
- for (Map.Entry<OSUStatus, String> entry : sStatusStrings.entrySet()) {
- sStatusEnums.put(entry.getValue().toLowerCase(), entry.getKey());
- }
-
- sErrorStrings.put(OSUError.SPPversionNotSupported, "SPP version not supported");
- sErrorStrings.put(OSUError.MOsNotSupported, "One or more mandatory MOs not supported");
- sErrorStrings.put(OSUError.CredentialsFailure,
- "Credentials cannot be provisioned at this time");
- sErrorStrings.put(OSUError.RemediationFailure,
- "Remediation cannot be completed at this time");
- sErrorStrings.put(OSUError.ProvisioningFailed,
- "Provisioning cannot be completed at this time");
- sErrorStrings.put(OSUError.ExistingCertificate, "Continue to use existing certificate");
- sErrorStrings.put(OSUError.CookieInvalid, "Cookie invalid");
- sErrorStrings.put(OSUError.WebSessionID,
- "No corresponding web-browser-connection Session ID");
- sErrorStrings.put(OSUError.PermissionDenied, "Permission denied");
- sErrorStrings.put(OSUError.CommandFailed, "Command failed");
- sErrorStrings.put(OSUError.MOaddOrUpdateFailed, "MO addition or update failed");
- sErrorStrings.put(OSUError.DeviceFull, "Device full");
- sErrorStrings.put(OSUError.BadTreeURI, "Bad management tree URI");
- sErrorStrings.put(OSUError.TooLarge, "Requested entity too large");
- sErrorStrings.put(OSUError.CommandNotAllowed, "Command not allowed");
- sErrorStrings.put(OSUError.UserAborted, "Command not executed due to user");
- sErrorStrings.put(OSUError.NotFound, "Not found");
- sErrorStrings.put(OSUError.Other, "Other");
-
- for (Map.Entry<OSUError, String> entry : sErrorStrings.entrySet()) {
- sErrorEnums.put(entry.getValue().toLowerCase(), entry.getKey());
- }
- Arrays.fill(INDENT, (byte) ' ');
- }
-
- public static String mapStatus(OSUStatus status) {
- return sStatusStrings.get(status);
- }
-
- public static OSUStatus mapStatus(String status) {
- return sStatusEnums.get(status.toLowerCase());
- }
-
- public static String mapError(OSUError error) {
- return sErrorStrings.get(error);
- }
-
- public static OSUError mapError(String error) {
- return sErrorEnums.get(error.toLowerCase());
- }
-
- public static void serializeString(String s, OutputStream out) throws IOException {
- byte[] octets = s.getBytes(StandardCharsets.UTF_8);
- byte[] prefix = String.format("%x:", octets.length).getBytes(StandardCharsets.UTF_8);
- out.write(prefix);
- out.write(octets);
- }
-
- public static void indent(int level, OutputStream out) throws IOException {
- out.write(INDENT, 0, level);
- }
-
- public static String deserializeString(InputStream in) throws IOException {
- StringBuilder prefix = new StringBuilder();
- for (; ; ) {
- byte b = (byte) in.read();
- if (b == '.')
- return null;
- else if (b == ':')
- break;
- else if (b > ' ')
- prefix.append((char) b);
- }
- int length = Integer.parseInt(prefix.toString(), 16);
- byte[] octets = new byte[length];
- int offset = 0;
- while (offset < octets.length) {
- int amount = in.read(octets, offset, octets.length - offset);
- if (amount <= 0)
- throw new EOFException();
- offset += amount;
- }
- return new String(octets, StandardCharsets.UTF_8);
- }
-
- public static String readURN(InputStream in) throws IOException {
- StringBuilder urn = new StringBuilder();
-
- for (; ; ) {
- byte b = (byte) in.read();
- if (b == ')')
- break;
- urn.append((char) b);
- }
- return urn.toString();
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/omadm/OMAConstructed.java b/packages/Osu/src/com/android/hotspot2/omadm/OMAConstructed.java
deleted file mode 100644
index e5285f294f9b..000000000000
--- a/packages/Osu/src/com/android/hotspot2/omadm/OMAConstructed.java
+++ /dev/null
@@ -1,169 +0,0 @@
-package com.android.hotspot2.omadm;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.Map;
-
-public class OMAConstructed extends OMANode {
- private final MultiValueMap<OMANode> mChildren;
-
- public OMAConstructed(OMAConstructed parent, String name, String context, String... avps) {
- this(parent, name, context, new MultiValueMap<OMANode>(), buildAttributes(avps));
- }
-
- protected OMAConstructed(OMAConstructed parent, String name, String context,
- MultiValueMap<OMANode> children, Map<String, String> avps) {
- super(parent, name, context, avps);
- mChildren = children;
- }
-
- @Override
- public OMANode addChild(String name, String context, String value, String pathString)
- throws IOException {
- if (pathString == null) {
- OMANode child = value != null ?
- new OMAScalar(this, name, context, value) :
- new OMAConstructed(this, name, context);
- mChildren.put(name, child);
- return child;
- } else {
- OMANode target = this;
- while (target.getParent() != null)
- target = target.getParent();
-
- for (String element : pathString.split("/")) {
- target = target.getChild(element);
- if (target == null)
- throw new IOException("No child node '" + element + "' in " + getPathString());
- else if (target.isLeaf())
- throw new IOException("Cannot add child to leaf node: " + getPathString());
- }
- return target.addChild(name, context, value, null);
- }
- }
-
- @Override
- public OMAConstructed reparent(OMAConstructed parent) {
- return new OMAConstructed(parent, getName(), getContext(), mChildren, getAttributes());
- }
-
- public void addChild(OMANode child) {
- mChildren.put(child.getName(), child.reparent(this));
- }
-
- public String getScalarValue(Iterator<String> path) throws OMAException {
- if (!path.hasNext()) {
- throw new OMAException("Path too short for " + getPathString());
- }
- String tag = path.next();
- OMANode child = mChildren.get(tag);
- if (child != null) {
- return child.getScalarValue(path);
- } else {
- return null;
- }
- }
-
- @Override
- public OMANode getListValue(Iterator<String> path) throws OMAException {
- if (!path.hasNext()) {
- return null;
- }
- String tag = path.next();
- OMANode child;
- if (tag.equals("?")) {
- child = mChildren.getSingletonValue();
- } else {
- child = mChildren.get(tag);
- }
-
- if (child == null) {
- return null;
- } else if (path.hasNext()) {
- return child.getListValue(path);
- } else {
- return child;
- }
- }
-
- @Override
- public boolean isLeaf() {
- return false;
- }
-
- @Override
- public Collection<OMANode> getChildren() {
- return Collections.unmodifiableCollection(mChildren.values());
- }
-
- public OMANode getChild(String name) {
- return mChildren.get(name);
- }
-
- public OMANode replaceNode(OMANode oldNode, OMANode newNode) {
- return mChildren.replace(oldNode.getName(), oldNode, newNode);
- }
-
- public OMANode removeNode(String key, OMANode node) {
- if (key.equals("?")) {
- return mChildren.remove(node);
- } else {
- return mChildren.remove(key, node);
- }
- }
-
- @Override
- public String getValue() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void toString(StringBuilder sb, int level) {
- sb.append(getPathString());
- if (getContext() != null) {
- sb.append(" (").append(getContext()).append(')');
- }
- sb.append('\n');
-
- for (OMANode node : mChildren.values()) {
- node.toString(sb, level + 1);
- }
- }
-
- @Override
- public void marshal(OutputStream out, int level) throws IOException {
- OMAConstants.indent(level, out);
- OMAConstants.serializeString(getName(), out);
- if (getContext() != null) {
- out.write(String.format("(%s)", getContext()).getBytes(StandardCharsets.UTF_8));
- }
- out.write(new byte[]{'+', '\n'});
-
- for (OMANode child : mChildren.values()) {
- child.marshal(out, level + 1);
- }
- OMAConstants.indent(level, out);
- out.write(".\n".getBytes(StandardCharsets.UTF_8));
- }
-
- @Override
- public void fillPayload(StringBuilder sb) {
- if (getContext() != null) {
- sb.append('<').append(MOTree.RTPropTag).append(">\n");
- sb.append('<').append(MOTree.TypeTag).append(">\n");
- sb.append('<').append(MOTree.DDFNameTag).append(">");
- sb.append(getContext());
- sb.append("</").append(MOTree.DDFNameTag).append(">\n");
- sb.append("</").append(MOTree.TypeTag).append(">\n");
- sb.append("</").append(MOTree.RTPropTag).append(">\n");
- }
-
- for (OMANode child : getChildren()) {
- child.toXml(sb);
- }
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/omadm/OMAException.java b/packages/Osu/src/com/android/hotspot2/omadm/OMAException.java
deleted file mode 100644
index 33a6e37970ed..000000000000
--- a/packages/Osu/src/com/android/hotspot2/omadm/OMAException.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.android.hotspot2.omadm;
-
-import java.io.IOException;
-
-public class OMAException extends IOException {
- public OMAException(String message) {
- super(message);
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/omadm/OMANode.java b/packages/Osu/src/com/android/hotspot2/omadm/OMANode.java
deleted file mode 100644
index a00f433aff51..000000000000
--- a/packages/Osu/src/com/android/hotspot2/omadm/OMANode.java
+++ /dev/null
@@ -1,163 +0,0 @@
-package com.android.hotspot2.omadm;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-public abstract class OMANode {
- private final OMAConstructed mParent;
- private final String mName;
- private final String mContext;
- private final Map<String, String> mAttributes;
-
- protected OMANode(OMAConstructed parent, String name, String context, Map<String, String> avps) {
- mParent = parent;
- mName = name;
- mContext = context;
- mAttributes = avps;
- }
-
- protected static Map<String, String> buildAttributes(String[] avps) {
- if (avps == null) {
- return null;
- }
- Map<String, String> attributes = new HashMap<>();
- for (int n = 0; n < avps.length; n += 2) {
- attributes.put(avps[n], avps[n + 1]);
- }
- return attributes;
- }
-
- protected Map<String, String> getAttributes() {
- return mAttributes;
- }
-
- public OMAConstructed getParent() {
- return mParent;
- }
-
- public String getName() {
- return mName;
- }
-
- public String getContext() {
- return mContext;
- }
-
- public List<String> getPath() {
- LinkedList<String> path = new LinkedList<>();
- for (OMANode node = this; node != null; node = node.getParent()) {
- path.addFirst(node.getName());
- }
- return path;
- }
-
- public String getPathString() {
- StringBuilder sb = new StringBuilder();
- for (String element : getPath()) {
- sb.append('/').append(element);
- }
- return sb.toString();
- }
-
- public abstract OMANode reparent(OMAConstructed parent);
-
- public abstract String getScalarValue(Iterator<String> path) throws OMAException;
-
- public abstract OMANode getListValue(Iterator<String> path) throws OMAException;
-
- public abstract boolean isLeaf();
-
- public abstract Collection<OMANode> getChildren();
-
- public abstract OMANode getChild(String name) throws OMAException;
-
- public abstract String getValue();
-
- public abstract OMANode addChild(String name, String context, String value, String path)
- throws IOException;
-
- public abstract void marshal(OutputStream out, int level) throws IOException;
-
- public abstract void toString(StringBuilder sb, int level);
-
- public abstract void fillPayload(StringBuilder sb);
-
- public void toXml(StringBuilder sb) {
- sb.append('<').append(MOTree.NodeTag);
- if (mAttributes != null && !mAttributes.isEmpty()) {
- for (Map.Entry<String, String> avp : mAttributes.entrySet()) {
- sb.append(' ').append(avp.getKey()).append("=\"").append(avp.getValue()).append('"');
- }
- }
- sb.append(">\n");
-
- sb.append('<').append(MOTree.NodeNameTag).append('>');
- sb.append(getName());
- sb.append("</").append(MOTree.NodeNameTag).append(">\n");
-
- fillPayload(sb);
-
- sb.append("</").append(MOTree.NodeTag).append(">\n");
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- toString(sb, 0);
- return sb.toString();
- }
-
- public static OMAConstructed unmarshal(InputStream in) throws IOException {
- OMANode node = buildNode(in, null);
- if (node == null || node.isLeaf()) {
- throw new IOException("Bad OMA tree");
- }
- unmarshal(in, (OMAConstructed) node);
- return (OMAConstructed) node;
- }
-
- private static void unmarshal(InputStream in, OMAConstructed parent) throws IOException {
- for (; ; ) {
- OMANode node = buildNode(in, parent);
- if (node == null) {
- return;
- } else if (!node.isLeaf()) {
- unmarshal(in, (OMAConstructed) node);
- }
- }
- }
-
- private static OMANode buildNode(InputStream in, OMAConstructed parent) throws IOException {
- String name = OMAConstants.deserializeString(in);
- if (name == null) {
- return null;
- }
-
- String urn = null;
- int next = in.read();
- if (next == '(') {
- urn = OMAConstants.readURN(in);
- next = in.read();
- }
-
- if (next == '=') {
- String value = OMAConstants.deserializeString(in);
- return parent.addChild(name, urn, value, null);
- } else if (next == '+') {
- if (parent != null) {
- return parent.addChild(name, urn, null, null);
- } else {
- return new OMAConstructed(null, name, urn);
- }
- } else {
- throw new IOException("Parse error: expected = or + after node name");
- }
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/omadm/OMAParser.java b/packages/Osu/src/com/android/hotspot2/omadm/OMAParser.java
deleted file mode 100644
index 21cc19a42ec2..000000000000
--- a/packages/Osu/src/com/android/hotspot2/omadm/OMAParser.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package com.android.hotspot2.omadm;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
-
-import java.io.IOException;
-import java.io.StringReader;
-
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-/**
- * Parses an OMA-DM XML tree.
- */
-public class OMAParser extends DefaultHandler {
- private XMLNode mRoot;
- private XMLNode mCurrent;
-
- public OMAParser() {
- mRoot = null;
- mCurrent = null;
- }
-
- public MOTree parse(String text, String urn) throws IOException, SAXException {
- try {
- SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
- parser.parse(new InputSource(new StringReader(text)), this);
- return new MOTree(mRoot, urn);
- } catch (ParserConfigurationException pce) {
- throw new SAXException(pce);
- }
- }
-
- @Override
- public void startElement(String uri, String localName, String qName, Attributes attributes)
- throws SAXException {
- XMLNode parent = mCurrent;
-
- mCurrent = new XMLNode(mCurrent, qName, attributes);
-
- if (mRoot == null)
- mRoot = mCurrent;
- else
- parent.addChild(mCurrent);
- }
-
- @Override
- public void endElement(String uri, String localName, String qName) throws SAXException {
- if (!qName.equals(mCurrent.getTag()))
- throw new SAXException("End tag '" + qName + "' doesn't match current node: " +
- mCurrent);
-
- try {
- mCurrent.close();
- } catch (IOException ioe) {
- throw new SAXException("Failed to close element", ioe);
- }
-
- mCurrent = mCurrent.getParent();
- }
-
- @Override
- public void characters(char[] ch, int start, int length) throws SAXException {
- mCurrent.addText(ch, start, length);
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/omadm/OMAScalar.java b/packages/Osu/src/com/android/hotspot2/omadm/OMAScalar.java
deleted file mode 100644
index a971ac4d7f3f..000000000000
--- a/packages/Osu/src/com/android/hotspot2/omadm/OMAScalar.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package com.android.hotspot2.omadm;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Map;
-
-public class OMAScalar extends OMANode {
- private final String mValue;
-
- public OMAScalar(OMAConstructed parent, String name, String context, String value,
- String ... avps) {
- this(parent, name, context, value, buildAttributes(avps));
- }
-
- public OMAScalar(OMAConstructed parent, String name, String context, String value,
- Map<String, String> avps) {
- super(parent, name, context, avps);
- mValue = value;
- }
-
- @Override
- public OMAScalar reparent(OMAConstructed parent) {
- return new OMAScalar(parent, getName(), getContext(), mValue, getAttributes());
- }
-
- public String getScalarValue(Iterator<String> path) throws OMAException {
- return mValue;
- }
-
- @Override
- public OMANode getListValue(Iterator<String> path) throws OMAException {
- throw new OMAException("Scalar encountered in list path: " + getPathString());
- }
-
- @Override
- public boolean isLeaf() {
- return true;
- }
-
- @Override
- public Collection<OMANode> getChildren() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getValue() {
- return mValue;
- }
-
- @Override
- public OMANode getChild(String name) throws OMAException {
- throw new OMAException("'" + getName() + "' is a scalar node");
- }
-
- @Override
- public OMANode addChild(String name, String context, String value, String path)
- throws IOException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void toString(StringBuilder sb, int level) {
- sb.append(getPathString()).append('=').append(mValue);
- if (getContext() != null) {
- sb.append(" (").append(getContext()).append(')');
- }
- sb.append('\n');
- }
-
- @Override
- public void marshal(OutputStream out, int level) throws IOException {
- OMAConstants.indent(level, out);
- OMAConstants.serializeString(getName(), out);
- out.write((byte) '=');
- OMAConstants.serializeString(getValue(), out);
- out.write((byte) '\n');
- }
-
- @Override
- public void fillPayload(StringBuilder sb) {
- sb.append('<').append(MOTree.ValueTag).append('>');
- sb.append(mValue);
- sb.append("</").append(MOTree.ValueTag).append(">\n");
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/omadm/XMLNode.java b/packages/Osu/src/com/android/hotspot2/omadm/XMLNode.java
deleted file mode 100644
index b77c820691a4..000000000000
--- a/packages/Osu/src/com/android/hotspot2/omadm/XMLNode.java
+++ /dev/null
@@ -1,240 +0,0 @@
-package com.android.hotspot2.omadm;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-public class XMLNode {
- private final String mTag;
- private final Map<String, NodeAttribute> mAttributes;
- private final List<XMLNode> mChildren;
- private final XMLNode mParent;
- private MOTree mMO;
- private StringBuilder mTextBuilder;
- private String mText;
-
- private static final String XML_SPECIAL_CHARS = "\"'<>&";
- private static final Set<Character> XML_SPECIAL = new HashSet<>();
- private static final String CDATA_OPEN = "<![CDATA[";
- private static final String CDATA_CLOSE = "]]>";
-
- static {
- for (int n = 0; n < XML_SPECIAL_CHARS.length(); n++) {
- XML_SPECIAL.add(XML_SPECIAL_CHARS.charAt(n));
- }
- }
-
- public XMLNode(XMLNode parent, String tag, Attributes attributes) throws SAXException {
- mTag = tag;
-
- mAttributes = new HashMap<>();
-
- if (attributes.getLength() > 0) {
- for (int n = 0; n < attributes.getLength(); n++)
- mAttributes.put(attributes.getQName(n), new NodeAttribute(attributes.getQName(n),
- attributes.getType(n), attributes.getValue(n)));
- }
-
- mParent = parent;
- mChildren = new ArrayList<>();
-
- mTextBuilder = new StringBuilder();
- }
-
- public XMLNode(XMLNode parent, String tag, Map<String, String> attributes) {
- mTag = tag;
-
- mAttributes = new HashMap<>(attributes == null ? 0 : attributes.size());
-
- if (attributes != null) {
- for (Map.Entry<String, String> entry : attributes.entrySet()) {
- mAttributes.put(entry.getKey(),
- new NodeAttribute(entry.getKey(), "", entry.getValue()));
- }
- }
-
- mParent = parent;
- mChildren = new ArrayList<>();
-
- mTextBuilder = new StringBuilder();
- }
-
- public void setText(String text) {
- mText = text;
- mTextBuilder = null;
- }
-
- public void addText(char[] chs, int start, int length) {
- String s = new String(chs, start, length);
- String trimmed = s.trim();
- if (trimmed.isEmpty())
- return;
-
- if (s.charAt(0) != trimmed.charAt(0))
- mTextBuilder.append(' ');
- mTextBuilder.append(trimmed);
- if (s.charAt(s.length() - 1) != trimmed.charAt(trimmed.length() - 1))
- mTextBuilder.append(' ');
- }
-
- public void addChild(XMLNode child) {
- mChildren.add(child);
- }
-
- public void close() throws IOException, SAXException {
- String text = mTextBuilder.toString().trim();
- StringBuilder filtered = new StringBuilder(text.length());
- for (int n = 0; n < text.length(); n++) {
- char ch = text.charAt(n);
- if (ch >= ' ')
- filtered.append(ch);
- }
-
- mText = filtered.toString();
- mTextBuilder = null;
-
- if (MOTree.hasMgmtTreeTag(mText)) {
- try {
- NodeAttribute urn = mAttributes.get(OMAConstants.SppMOAttribute);
- OMAParser omaParser = new OMAParser();
- mMO = omaParser.parse(mText, urn != null ? urn.getValue() : null);
- } catch (SAXException | IOException e) {
- mMO = null;
- }
- }
- }
-
- public String getTag() {
- return mTag;
- }
-
- public String getNameSpace() throws OMAException {
- String[] nsn = mTag.split(":");
- if (nsn.length != 2) {
- throw new OMAException("Non-namespaced tag: '" + mTag + "'");
- }
- return nsn[0];
- }
-
- public String getStrippedTag() throws OMAException {
- String[] nsn = mTag.split(":");
- if (nsn.length != 2) {
- throw new OMAException("Non-namespaced tag: '" + mTag + "'");
- }
- return nsn[1].toLowerCase();
- }
-
- public XMLNode getSoleChild() throws OMAException {
- if (mChildren.size() != 1) {
- throw new OMAException("Expected exactly one child to " + mTag);
- }
- return mChildren.get(0);
- }
-
- public XMLNode getParent() {
- return mParent;
- }
-
- public String getText() {
- return mText;
- }
-
- public Map<String, NodeAttribute> getAttributes() {
- return Collections.unmodifiableMap(mAttributes);
- }
-
- public Map<String, String> getTextualAttributes() {
- Map<String, String> map = new HashMap<>(mAttributes.size());
- for (Map.Entry<String, NodeAttribute> entry : mAttributes.entrySet()) {
- map.put(entry.getKey(), entry.getValue().getValue());
- }
- return map;
- }
-
- public String getAttributeValue(String name) {
- NodeAttribute nodeAttribute = mAttributes.get(name);
- return nodeAttribute != null ? nodeAttribute.getValue() : null;
- }
-
- public List<XMLNode> getChildren() {
- return mChildren;
- }
-
- public MOTree getMOTree() {
- return mMO;
- }
-
- private void toString(char[] indent, StringBuilder sb) {
- Arrays.fill(indent, ' ');
-
- sb.append(indent).append('<').append(mTag);
- for (Map.Entry<String, NodeAttribute> entry : mAttributes.entrySet()) {
- sb.append(' ').append(entry.getKey()).append("='")
- .append(entry.getValue().getValue()).append('\'');
- }
-
- if (mText != null && !mText.isEmpty()) {
- sb.append('>').append(escapeCdata(mText)).append("</").append(mTag).append(">\n");
- } else if (mChildren.isEmpty()) {
- sb.append("/>\n");
- } else {
- sb.append(">\n");
- char[] subIndent = Arrays.copyOf(indent, indent.length + 2);
- for (XMLNode child : mChildren) {
- child.toString(subIndent, sb);
- }
- sb.append(indent).append("</").append(mTag).append(">\n");
- }
- }
-
- private static String escapeCdata(String text) {
- if (!escapable(text)) {
- return text;
- }
-
- // Any appearance of ]]> in the text must be split into "]]" | "]]>" | <![CDATA[ | ">"
- // i.e. "split the sequence by putting a close CDATA and a new open CDATA before the '>'
- StringBuilder sb = new StringBuilder();
- sb.append(CDATA_OPEN);
- int start = 0;
- for (; ; ) {
- int etoken = text.indexOf(CDATA_CLOSE);
- if (etoken >= 0) {
- sb.append(text.substring(start, etoken + 2)).append(CDATA_CLOSE).append(CDATA_OPEN);
- start = etoken + 2;
- } else {
- if (start < text.length() - 1) {
- sb.append(text.substring(start));
- }
- break;
- }
- }
- sb.append(CDATA_CLOSE);
- return sb.toString();
- }
-
- private static boolean escapable(String s) {
- for (int n = 0; n < s.length(); n++) {
- if (XML_SPECIAL.contains(s.charAt(n))) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- toString(new char[0], sb);
- return sb.toString();
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/ClientKeyManager.java b/packages/Osu/src/com/android/hotspot2/osu/ClientKeyManager.java
deleted file mode 100644
index cfc84bbc6225..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/ClientKeyManager.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package com.android.hotspot2.osu;
-
-import android.util.Log;
-
-import com.android.hotspot2.flow.PlatformAdapter;
-import com.android.hotspot2.pps.HomeSP;
-
-import java.io.IOException;
-import java.net.Socket;
-import java.security.GeneralSecurityException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.Principal;
-import java.security.PrivateKey;
-import java.security.cert.Certificate;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.net.ssl.X509KeyManager;
-
-public class ClientKeyManager implements X509KeyManager {
- private final KeyStore mKeyStore;
- private final Map<OSUCertType, String> mAliasMap;
- private final Map<OSUCertType, Object> mTempKeys;
-
- private static final String sTempAlias = "client-alias";
-
- public ClientKeyManager(HomeSP homeSP, KeyStore keyStore) throws IOException {
- mKeyStore = keyStore;
- mAliasMap = new HashMap<>();
- mAliasMap.put(OSUCertType.AAA, PlatformAdapter.CERT_CLT_CA_ALIAS + homeSP.getFQDN());
- mAliasMap.put(OSUCertType.Client, PlatformAdapter.CERT_CLT_CERT_ALIAS + homeSP.getFQDN());
- mAliasMap.put(OSUCertType.PrivateKey, PlatformAdapter.CERT_CLT_KEY_ALIAS + homeSP.getFQDN());
- mTempKeys = new HashMap<>();
- }
-
- public void reloadKeys(Map<OSUCertType, List<X509Certificate>> certs, PrivateKey key)
- throws IOException {
- List<X509Certificate> clientCerts = certs.get(OSUCertType.Client);
- X509Certificate[] certArray = new X509Certificate[clientCerts.size()];
- int n = 0;
- for (X509Certificate cert : clientCerts) {
- certArray[n++] = cert;
- }
- mTempKeys.put(OSUCertType.Client, certArray);
- mTempKeys.put(OSUCertType.PrivateKey, key);
- }
-
- @Override
- public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
- if (mTempKeys.isEmpty()) {
- return mAliasMap.get(OSUCertType.Client);
- } else {
- return sTempAlias;
- }
- }
-
- @Override
- public String[] getClientAliases(String keyType, Principal[] issuers) {
- if (mTempKeys.isEmpty()) {
- String alias = mAliasMap.get(OSUCertType.Client);
- return alias != null ? new String[]{alias} : null;
- } else {
- return new String[]{sTempAlias};
- }
- }
-
- @Override
- public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String[] getServerAliases(String keyType, Principal[] issuers) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public X509Certificate[] getCertificateChain(String alias) {
- if (mTempKeys.isEmpty()) {
- if (!mAliasMap.get(OSUCertType.Client).equals(alias)) {
- Log.w(OSUManager.TAG, "Bad cert alias requested: '" + alias + "'");
- return null;
- }
- try {
- Certificate cert = mKeyStore.getCertificate(alias);
- return new X509Certificate[] {(X509Certificate) cert};
- } catch (KeyStoreException kse) {
- Log.w(OSUManager.TAG, "Failed to retrieve certificates: " + kse);
- return null;
- }
- } else if (sTempAlias.equals(alias)) {
- return (X509Certificate[]) mTempKeys.get(OSUCertType.Client);
- } else {
- Log.w(OSUManager.TAG, "Bad cert alias requested: '" + alias + "'");
- return null;
- }
- }
-
- @Override
- public PrivateKey getPrivateKey(String alias) {
- if (mTempKeys.isEmpty()) {
- if (!mAliasMap.get(OSUCertType.Client).equals(alias)) {
- Log.w(OSUManager.TAG, "Bad key alias requested: '" + alias + "'");
- }
- try {
- return (PrivateKey) mKeyStore.getKey(mAliasMap.get(OSUCertType.PrivateKey), null);
- } catch (GeneralSecurityException gse) {
- Log.w(OSUManager.TAG, "Failed to retrieve private key: " + gse);
- return null;
- }
- } else if (sTempAlias.equals(alias)) {
- return (PrivateKey) mTempKeys.get(OSUCertType.PrivateKey);
- } else {
- Log.w(OSUManager.TAG, "Bad cert alias requested: '" + alias + "'");
- return null;
- }
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/ExchangeCompleteResponse.java b/packages/Osu/src/com/android/hotspot2/osu/ExchangeCompleteResponse.java
deleted file mode 100644
index fe23b5c04391..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/ExchangeCompleteResponse.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.android.hotspot2.osu;
-
-import com.android.hotspot2.omadm.OMAException;
-import com.android.hotspot2.omadm.XMLNode;
-
- /*
- <xsd:element name="sppExchangeComplete">
- <xsd:annotation>
- <xsd:documentation>SOAP method used by SPP server to end session.</xsd:documentation>
- </xsd:annotation>
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element ref="sppError" minOccurs="0"/>
- <xsd:any namespace="##other" maxOccurs="unbounded" minOccurs="0"/>
- </xsd:sequence>
- <xsd:attribute ref="sppVersion" use="required"/>
- <xsd:attribute ref="sppStatus" use="required"/>
- <xsd:attribute ref="sessionID" use="required"/>
- <xsd:anyAttribute namespace="##other"/>
- </xsd:complexType>
- </xsd:element>
- */
-
-public class ExchangeCompleteResponse extends OSUResponse {
- public ExchangeCompleteResponse(XMLNode root) throws OMAException {
- super(root, OSUMessageType.ExchangeComplete);
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/ExecCommand.java b/packages/Osu/src/com/android/hotspot2/osu/ExecCommand.java
deleted file mode 100644
index 38a394727f54..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/ExecCommand.java
+++ /dev/null
@@ -1,3 +0,0 @@
-package com.android.hotspot2.osu;
-
-public enum ExecCommand {Browser, GetCert, UseClientCertTLS, UploadMO}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/HTTPHandler.java b/packages/Osu/src/com/android/hotspot2/osu/HTTPHandler.java
deleted file mode 100644
index 4b583df1ce44..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/HTTPHandler.java
+++ /dev/null
@@ -1,180 +0,0 @@
-package com.android.hotspot2.osu;
-
-import android.util.Log;
-
-import com.android.hotspot2.utils.HTTPMessage;
-import com.android.hotspot2.utils.HTTPRequest;
-import com.android.hotspot2.utils.HTTPResponse;
-
-import com.android.org.conscrypt.OpenSSLSocketImpl;
-
-import org.xml.sax.SAXException;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.Socket;
-import java.net.URL;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.security.GeneralSecurityException;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLSocket;
-import javax.xml.parsers.ParserConfigurationException;
-
-public class HTTPHandler implements AutoCloseable {
- private final Charset mCharset;
- private final OSUSocketFactory mSocketFactory;
- private Socket mSocket;
- private BufferedOutputStream mOut;
- private BufferedInputStream mIn;
- private final String mUser;
- private final byte[] mPassword;
- private boolean mHTTPAuthPerformed;
- private static final AtomicInteger sSequence = new AtomicInteger();
-
- public HTTPHandler(Charset charset, OSUSocketFactory socketFactory) throws IOException {
- this(charset, socketFactory, null, null);
- }
-
- public HTTPHandler(Charset charset, OSUSocketFactory socketFactory,
- String user, byte[] password) throws IOException {
- mCharset = charset;
- mSocketFactory = socketFactory;
- mSocket = mSocketFactory.createSocket();
- mOut = new BufferedOutputStream(mSocket.getOutputStream());
- mIn = new BufferedInputStream(mSocket.getInputStream());
- mUser = user;
- mPassword = password;
- }
-
- public boolean isHTTPAuthPerformed() {
- return mHTTPAuthPerformed;
- }
-
- public X509Certificate getOSUCertificate(URL osu) throws GeneralSecurityException {
- return mSocketFactory.getOSUCertificate(osu);
- }
-
- public void renegotiate(Map<OSUCertType, List<X509Certificate>> certs, PrivateKey key)
- throws IOException {
- if (!(mSocket instanceof SSLSocket)) {
- throw new IOException("Not a TLS connection");
- }
- if (certs != null) {
- mSocketFactory.reloadKeys(certs, key);
- }
- ((SSLSocket) mSocket).startHandshake();
- }
-
- public byte[] getTLSUnique() throws SSLException {
- if (mSocket instanceof OpenSSLSocketImpl) {
- return ((OpenSSLSocketImpl) mSocket).getChannelId();
- }
- return null;
- }
-
- public OSUResponse exchangeSOAP(URL url, String message) throws IOException {
- HTTPResponse response = exchangeWithRetry(url, message, HTTPMessage.Method.POST,
- HTTPMessage.ContentTypeSOAP);
- if (response.getStatusCode() >= 300) {
- throw new IOException("Bad HTTP status code " + response.getStatusCode());
- }
- try {
- SOAPParser parser = new SOAPParser(response.getPayloadStream());
- return parser.getResponse();
- } catch (ParserConfigurationException | SAXException e) {
- ByteBuffer x = response.getPayload();
- byte[] b = new byte[x.remaining()];
- x.get(b);
- Log.w("XML", "Bad: '" + new String(b, StandardCharsets.ISO_8859_1));
- throw new IOException(e);
- }
- }
-
- public ByteBuffer exchangeBinary(URL url, String message, String contentType)
- throws IOException {
- HTTPResponse response =
- exchangeWithRetry(url, message, HTTPMessage.Method.POST, contentType);
- return response.getBinaryPayload();
- }
-
- public InputStream doGet(URL url) throws IOException {
- HTTPResponse response = exchangeWithRetry(url, null, HTTPMessage.Method.GET, null);
- return response.getPayloadStream();
- }
-
- public HTTPResponse doGetHTTP(URL url) throws IOException {
- return exchangeWithRetry(url, null, HTTPMessage.Method.GET, null);
- }
-
- private HTTPResponse exchangeWithRetry(URL url, String message, HTTPMessage.Method method,
- String contentType) throws IOException {
- HTTPResponse response = null;
- int retry = 0;
- for (; ; ) {
- try {
- response = httpExchange(url, message, method, contentType);
- break;
- } catch (IOException ioe) {
- close();
- retry++;
- if (retry > 3) {
- break;
- }
- Log.d(OSUManager.TAG, "Failed HTTP exchange, retry " + retry);
- mSocket = mSocketFactory.createSocket();
- mOut = new BufferedOutputStream(mSocket.getOutputStream());
- mIn = new BufferedInputStream(mSocket.getInputStream());
- }
- }
- if (response == null) {
- throw new IOException("Failed to establish connection to peer");
- }
- return response;
- }
-
- private HTTPResponse httpExchange(URL url, String message, HTTPMessage.Method method,
- String contentType)
- throws IOException {
- HTTPRequest request = new HTTPRequest(message, mCharset, method, url, contentType, false);
- request.send(mOut);
- HTTPResponse response = new HTTPResponse(mIn);
- Log.d(OSUManager.TAG, "HTTP code " + response.getStatusCode() + ", user " + mUser +
- ", pw " + (mPassword != null ? '\'' + new String(mPassword) + '\'' : "-"));
- if (response.getStatusCode() == 401) {
- if (mUser == null) {
- throw new IOException("Missing user name for HTTP authentication");
- }
- try {
- request = new HTTPRequest(message, StandardCharsets.ISO_8859_1, method, url,
- contentType, true);
- request.doAuthenticate(response, mUser, mPassword, url,
- sSequence.incrementAndGet());
- request.send(mOut);
- mHTTPAuthPerformed = true;
- } catch (GeneralSecurityException gse) {
- throw new IOException(gse);
- }
-
- response = new HTTPResponse(mIn);
- }
- return response;
- }
-
- public void close() throws IOException {
- mSocket.shutdownInput();
- mSocket.shutdownOutput();
- mSocket.close();
- mIn.close();
- mOut.close();
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/IconCache.java b/packages/Osu/src/com/android/hotspot2/osu/IconCache.java
deleted file mode 100644
index bd8a018a5f0b..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/IconCache.java
+++ /dev/null
@@ -1,337 +0,0 @@
-package com.android.hotspot2.osu;
-
-import android.util.Log;
-
-import com.android.anqp.HSIconFileElement;
-import com.android.anqp.IconInfo;
-import com.android.hotspot2.Utils;
-import com.android.hotspot2.flow.OSUInfo;
-
-import java.net.ProtocolException;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-import static com.android.anqp.Constants.ANQPElementType.HSIconFile;
-
-public class IconCache extends Thread {
- // Preferred icon parameters
- private static final Set<String> ICON_TYPES =
- new HashSet<>(Arrays.asList("image/png", "image/jpeg"));
- private static final int ICON_WIDTH = 64;
- private static final int ICON_HEIGHT = 64;
- public static final Locale LOCALE = java.util.Locale.getDefault();
-
- private static final int MAX_RETRY = 3;
- private static final long REQUERY_TIME = 5000L;
- private static final long REQUERY_TIMEOUT = 120000L;
-
- private final OSUManager mOsuManager;
- private final Map<EssKey, Map<String, FileEntry>> mPending;
- private final Map<EssKey, Map<String, HSIconFileElement>> mCache;
-
- private static class EssKey {
- private final int mAnqpDomainId;
- private final long mBssid;
- private final long mHessid;
- private final String mSsid;
-
- private EssKey(OSUInfo osuInfo) {
- mAnqpDomainId = osuInfo.getAnqpDomID();
- mBssid = osuInfo.getBSSID();
- mHessid = osuInfo.getHESSID();
- mSsid = osuInfo.getAdvertisingSsid();
- }
-
- /*
- * ANQP ID 1 ANQP ID 2
- * 0 0 BSSID equality
- * 0 X BSSID equality
- * Y X BSSID equality
- * X X Then:
- *
- * HESSID1 HESSID2
- * 0 0 compare SSIDs
- * 0 X not equal
- * Y X not equal
- * X X equal
- */
-
- @Override
- public boolean equals(Object thatObject) {
- if (this == thatObject) {
- return true;
- }
- if (thatObject == null || getClass() != thatObject.getClass()) {
- return false;
- }
-
- EssKey that = (EssKey) thatObject;
- if (mAnqpDomainId != 0 && mAnqpDomainId == that.mAnqpDomainId) {
- return mHessid == that.mHessid
- && (mHessid != 0 || mSsid.equals(that.mSsid));
- } else {
- return mBssid == that.mBssid;
- }
- }
-
- @Override
- public int hashCode() {
- if (mAnqpDomainId == 0) {
- return (int) (mBssid ^ (mBssid >>> 32));
- } else if (mHessid != 0) {
- return mAnqpDomainId * 31 + (int) (mHessid ^ (mHessid >>> 32));
- } else {
- return mAnqpDomainId * 31 + mSsid.hashCode();
- }
- }
-
- @Override
- public String toString() {
- if (mAnqpDomainId == 0) {
- return String.format("BSS %012x", mBssid);
- } else if (mHessid != 0) {
- return String.format("ESS %012x [%d]", mBssid, mAnqpDomainId);
- } else {
- return String.format("ESS '%s' [%d]", mSsid, mAnqpDomainId);
- }
- }
- }
-
- private static class FileEntry {
- private final String mFileName;
- private int mRetry = 0;
- private final long mTimestamp;
- private final LinkedList<OSUInfo> mQueued;
- private final Set<Long> mBssids;
-
- private FileEntry(OSUInfo osuInfo, String fileName) {
- mFileName = fileName;
- mQueued = new LinkedList<>();
- mBssids = new HashSet<>();
- mQueued.addLast(osuInfo);
- mBssids.add(osuInfo.getBSSID());
- mTimestamp = System.currentTimeMillis();
- }
-
- private void enqueu(OSUInfo osuInfo) {
- mQueued.addLast(osuInfo);
- mBssids.add(osuInfo.getBSSID());
- }
-
- private int update(long bssid, HSIconFileElement iconFileElement) {
- if (!mBssids.contains(bssid)) {
- return 0;
- }
- Log.d(OSUManager.TAG, "Updating icon on " + mQueued.size() + " osus");
- for (OSUInfo osuInfo : mQueued) {
- osuInfo.setIconFileElement(iconFileElement, mFileName);
- }
- return mQueued.size();
- }
-
- private int getAndIncrementRetry() {
- return mRetry++;
- }
-
- private long getTimestamp() {
- return mTimestamp;
- }
-
- public String getFileName() {
- return mFileName;
- }
-
- private long getLastBssid() {
- return mQueued.getLast().getBSSID();
- }
-
- @Override
- public String toString() {
- return String.format("'%s', retry %d, age %d, BSSIDs: %s",
- mFileName, mRetry,
- System.currentTimeMillis() - mTimestamp, Utils.bssidsToString(mBssids));
- }
- }
-
- public IconCache(OSUManager osuManager) {
- mOsuManager = osuManager;
- mPending = new HashMap<>();
- mCache = new HashMap<>();
- }
-
- public int resolveIcons(Collection<OSUInfo> osuInfos) {
- Set<EssKey> current = new HashSet<>();
- int modCount = 0;
- for (OSUInfo osuInfo : osuInfos) {
- EssKey key = new EssKey(osuInfo);
- current.add(key);
-
- if (osuInfo.getIconStatus() == OSUInfo.IconStatus.NotQueried) {
- List<IconInfo> iconInfo =
- osuInfo.getIconInfo(LOCALE, ICON_TYPES, ICON_WIDTH, ICON_HEIGHT);
- if (iconInfo.isEmpty()) {
- osuInfo.setIconStatus(OSUInfo.IconStatus.NotAvailable);
- continue;
- }
-
- String fileName = iconInfo.get(0).getFileName();
- HSIconFileElement iconFileElement = get(key, fileName);
- if (iconFileElement != null) {
- osuInfo.setIconFileElement(iconFileElement, fileName);
- Log.d(OSUManager.TAG, "Icon cache hit for " + osuInfo + "/" + fileName);
- modCount++;
- } else {
- FileEntry fileEntry = enqueue(key, fileName, osuInfo);
- if (fileEntry != null) {
- Log.d(OSUManager.TAG, "Initiating icon query for "
- + osuInfo + "/" + fileName);
- mOsuManager.doIconQuery(osuInfo.getBSSID(), fileName);
- } else {
- Log.d(OSUManager.TAG, "Piggybacking icon query for "
- + osuInfo + "/" + fileName);
- }
- }
- }
- }
-
- // Drop all non-current ESS's
- Iterator<EssKey> pendingKeys = mPending.keySet().iterator();
- while (pendingKeys.hasNext()) {
- EssKey key = pendingKeys.next();
- if (!current.contains(key)) {
- pendingKeys.remove();
- }
- }
- Iterator<EssKey> cacheKeys = mCache.keySet().iterator();
- while (cacheKeys.hasNext()) {
- EssKey key = cacheKeys.next();
- if (!current.contains(key)) {
- cacheKeys.remove();
- }
- }
- return modCount;
- }
-
- public HSIconFileElement getIcon(OSUInfo osuInfo) {
- List<IconInfo> iconInfos = osuInfo.getIconInfo(LOCALE, ICON_TYPES, ICON_WIDTH, ICON_HEIGHT);
- if (iconInfos == null || iconInfos.isEmpty()) {
- return null;
- }
- EssKey key = new EssKey(osuInfo);
- Map<String, HSIconFileElement> fileMap = mCache.get(key);
- return fileMap != null ? fileMap.get(iconInfos.get(0).getFileName()) : null;
- }
-
- public int notifyIconReceived(long bssid, String fileName, byte[] iconData) {
- Log.d(OSUManager.TAG, String.format("Icon '%s':%d received from %012x",
- fileName, iconData != null ? iconData.length : -1, bssid));
- if (fileName == null || iconData == null) {
- return 0;
- }
-
- HSIconFileElement iconFileElement;
- try {
- iconFileElement = new HSIconFileElement(HSIconFile,
- ByteBuffer.wrap(iconData).order(ByteOrder.LITTLE_ENDIAN));
- } catch (ProtocolException | BufferUnderflowException e) {
- Log.e(OSUManager.TAG, "Failed to parse ANQP icon file: " + e);
- return 0;
- }
-
- int updates = 0;
- Iterator<Map.Entry<EssKey, Map<String, FileEntry>>> entries =
- mPending.entrySet().iterator();
-
- while (entries.hasNext()) {
- Map.Entry<EssKey, Map<String, FileEntry>> entry = entries.next();
-
- Map<String, FileEntry> fileMap = entry.getValue();
- FileEntry fileEntry = fileMap.get(fileName);
- updates = fileEntry.update(bssid, iconFileElement);
- if (updates > 0) {
- put(entry.getKey(), fileName, iconFileElement);
- fileMap.remove(fileName);
- if (fileMap.isEmpty()) {
- entries.remove();
- }
- break;
- }
- }
- return updates;
- }
-
- public void tick(boolean wifiOff) {
- if (wifiOff) {
- mPending.clear();
- mCache.clear();
- return;
- }
-
- Iterator<Map.Entry<EssKey, Map<String, FileEntry>>> entries =
- mPending.entrySet().iterator();
-
- long now = System.currentTimeMillis();
- while (entries.hasNext()) {
- Map<String, FileEntry> fileMap = entries.next().getValue();
- Iterator<Map.Entry<String, FileEntry>> fileEntries = fileMap.entrySet().iterator();
- while (fileEntries.hasNext()) {
- FileEntry fileEntry = fileEntries.next().getValue();
- long age = now - fileEntry.getTimestamp();
- if (age > REQUERY_TIMEOUT || fileEntry.getAndIncrementRetry() > MAX_RETRY) {
- fileEntries.remove();
- } else if (age > REQUERY_TIME) {
- mOsuManager.doIconQuery(fileEntry.getLastBssid(), fileEntry.getFileName());
- }
- }
- if (fileMap.isEmpty()) {
- entries.remove();
- }
- }
- }
-
- private HSIconFileElement get(EssKey key, String fileName) {
- Map<String, HSIconFileElement> fileMap = mCache.get(key);
- if (fileMap == null) {
- return null;
- }
- return fileMap.get(fileName);
- }
-
- private void put(EssKey key, String fileName, HSIconFileElement icon) {
- Map<String, HSIconFileElement> fileMap = mCache.get(key);
- if (fileMap == null) {
- fileMap = new HashMap<>();
- mCache.put(key, fileMap);
- }
- fileMap.put(fileName, icon);
- }
-
- private FileEntry enqueue(EssKey key, String fileName, OSUInfo osuInfo) {
- Map<String, FileEntry> entryMap = mPending.get(key);
- if (entryMap == null) {
- entryMap = new HashMap<>();
- mPending.put(key, entryMap);
- }
-
- FileEntry fileEntry = entryMap.get(fileName);
- osuInfo.setIconStatus(OSUInfo.IconStatus.InProgress);
- if (fileEntry == null) {
- fileEntry = new FileEntry(osuInfo, fileName);
- entryMap.put(fileName, fileEntry);
- return fileEntry;
- }
- fileEntry.enqueu(osuInfo);
- return null;
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/OSUCache.java b/packages/Osu/src/com/android/hotspot2/osu/OSUCache.java
deleted file mode 100644
index 260fb723ab36..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/OSUCache.java
+++ /dev/null
@@ -1,178 +0,0 @@
-package com.android.hotspot2.osu;
-
-import android.net.wifi.AnqpInformationElement;
-import android.net.wifi.ScanResult;
-import android.util.Log;
-
-import com.android.anqp.Constants;
-import com.android.anqp.HSOsuProvidersElement;
-import com.android.anqp.OSUProvider;
-
-import java.net.ProtocolException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * This class holds a stable set of OSU information as well as scan results based on a trail of
- * scan results.
- * The purpose of this class is to provide a stable set of information over a a limited span of
- * time (SCAN_BATCH_HISTORY_SIZE scan batches) so that OSU entries in the selection list does not
- * come and go with temporarily lost scan results.
- * The stable set of scan results are used by the remediation flow to retrieve ANQP information
- * for the current network to determine whether the currently associated network is a roaming
- * network for the Home SP whose timer has currently fired.
- */
-public class OSUCache {
- private static final int SCAN_BATCH_HISTORY_SIZE = 8;
-
- private int mInstant;
- private final Map<OSUProvider, ScanResult> mBatchedOSUs = new HashMap<>();
- private final Map<OSUProvider, ScanInstance> mCache = new HashMap<>();
-
- private static class ScanInstance {
- private final ScanResult mScanResult;
- private int mInstant;
-
- private ScanInstance(ScanResult scanResult, int instant) {
- mScanResult = scanResult;
- mInstant = instant;
- }
-
- public ScanResult getScanResult() {
- return mScanResult;
- }
-
- public int getInstant() {
- return mInstant;
- }
-
- private boolean bssidEqual(ScanResult scanResult) {
- return mScanResult.BSSID.equals(scanResult.BSSID);
- }
-
- private void updateInstant(int newInstant) {
- mInstant = newInstant;
- }
-
- @Override
- public String toString() {
- return mScanResult.SSID + " @ " + mInstant;
- }
- }
-
- public OSUCache() {
- mInstant = 0;
- }
-
- private void clear() {
- mBatchedOSUs.clear();
- }
-
- public void clearAll() {
- clear();
- mCache.clear();
- }
-
- public Map<OSUProvider, ScanResult> pushScanResults(Collection<ScanResult> scanResults) {
- for (ScanResult scanResult : scanResults) {
- AnqpInformationElement[] osuInfo = scanResult.anqpElements;
- if (osuInfo != null && osuInfo.length > 0) {
- Log.d(OSUManager.TAG, scanResult.SSID +
- " has " + osuInfo.length + " ANQP elements");
- putResult(scanResult, osuInfo);
- }
- }
- return scanEnd();
- }
-
- private void putResult(ScanResult scanResult, AnqpInformationElement[] elements) {
- for (AnqpInformationElement ie : elements) {
- Log.d(OSUManager.TAG, String.format("ANQP IE %d vid %x size %d", ie.getElementId(),
- ie.getVendorId(), ie.getPayload().length));
- if (ie.getElementId() == AnqpInformationElement.HS_OSU_PROVIDERS
- && ie.getVendorId() == AnqpInformationElement.HOTSPOT20_VENDOR_ID) {
- try {
- HSOsuProvidersElement providers = new HSOsuProvidersElement(
- Constants.ANQPElementType.HSOSUProviders,
- ByteBuffer.wrap(ie.getPayload()).order(ByteOrder.LITTLE_ENDIAN));
-
- putProviders(scanResult, providers);
- } catch (ProtocolException pe) {
- Log.w(OSUManager.TAG,
- "Failed to parse OSU element: " + pe);
- }
- }
- }
- }
-
- private void putProviders(ScanResult scanResult, HSOsuProvidersElement osuProviders) {
- Log.d(OSUManager.TAG, osuProviders.getProviders().size() + " OSU providers in element");
- for (OSUProvider provider : osuProviders.getProviders()) {
- // Make a predictive put
- ScanResult existing = mBatchedOSUs.put(provider, scanResult);
- if (existing != null && existing.level > scanResult.level) {
- // But undo it if the entry already held a better RSSI
- mBatchedOSUs.put(provider, existing);
- }
- }
- }
-
- private Map<OSUProvider, ScanResult> scanEnd() {
- // Update the trail of OSU Providers:
- int changes = 0;
- Map<OSUProvider, ScanInstance> aged = new HashMap<>(mCache);
- for (Map.Entry<OSUProvider, ScanResult> entry : mBatchedOSUs.entrySet()) {
- ScanInstance current = aged.remove(entry.getKey());
- if (current == null || !current.bssidEqual(entry.getValue())) {
- mCache.put(entry.getKey(), new ScanInstance(entry.getValue(), mInstant));
- changes++;
- if (current == null) {
- Log.d(OSUManager.TAG,
- "Add OSU " + entry.getKey() + " from " + entry.getValue().SSID);
- } else {
- Log.d(OSUManager.TAG, "Update OSU " + entry.getKey() + " with " +
- entry.getValue().SSID + " to " + current);
- }
- } else {
- Log.d(OSUManager.TAG, "Existing OSU " + entry.getKey() + ", "
- + current.getInstant() + " -> " + mInstant);
- current.updateInstant(mInstant);
- }
- }
-
- for (Map.Entry<OSUProvider, ScanInstance> entry : aged.entrySet()) {
- if (mInstant - entry.getValue().getInstant() > SCAN_BATCH_HISTORY_SIZE) {
- Log.d(OSUManager.TAG, "Remove OSU " + entry.getKey() + ", "
- + entry.getValue().getInstant() + " @ " + mInstant);
- mCache.remove(entry.getKey());
- changes++;
- }
- }
-
- mInstant++;
- clear();
-
- // Return the latest results if there were any changes from last batch
- if (changes > 0) {
- Map<OSUProvider, ScanResult> results = new HashMap<>(mCache.size());
- for (Map.Entry<OSUProvider, ScanInstance> entry : mCache.entrySet()) {
- results.put(entry.getKey(), entry.getValue().getScanResult());
- }
- return results;
- } else {
- return null;
- }
- }
-
- private static String toBSSIDStrings(Set<Long> bssids) {
- StringBuilder sb = new StringBuilder();
- for (Long bssid : bssids) {
- sb.append(String.format(" %012x", bssid));
- }
- return sb.toString();
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/OSUCertType.java b/packages/Osu/src/com/android/hotspot2/osu/OSUCertType.java
deleted file mode 100644
index 91d7f727e0dc..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/OSUCertType.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.android.hotspot2.osu;
-
-public enum OSUCertType {
- CA,
- Client,
- AAA,
- Remediation,
- Policy,
- PrivateKey
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/OSUClient.java b/packages/Osu/src/com/android/hotspot2/osu/OSUClient.java
deleted file mode 100644
index 8179a631dd29..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/OSUClient.java
+++ /dev/null
@@ -1,540 +0,0 @@
-package com.android.hotspot2.osu;
-
-/*
- * policy-server.r2-testbed IN A 10.123.107.107
- * remediation-server.r2-testbed IN A 10.123.107.107
- * subscription-server.r2-testbed IN A 10.123.107.107
- * www.r2-testbed IN A 10.123.107.107
- * osu-server.r2-testbed-rks IN A 10.123.107.107
- * policy-server.r2-testbed-rks IN A 10.123.107.107
- * remediation-server.r2-testbed-rks IN A 10.123.107.107
- * subscription-server.r2-testbed-rks IN A 10.123.107.107
- */
-
-import android.content.Context;
-import android.content.Intent;
-import android.net.Network;
-import android.util.Log;
-
-import com.android.hotspot2.OMADMAdapter;
-import com.android.hotspot2.est.ESTHandler;
-import com.android.hotspot2.flow.OSUInfo;
-import com.android.hotspot2.flow.PlatformAdapter;
-import com.android.hotspot2.omadm.OMAConstants;
-import com.android.hotspot2.omadm.OMANode;
-import com.android.hotspot2.osu.commands.BrowserURI;
-import com.android.hotspot2.osu.commands.ClientCertInfo;
-import com.android.hotspot2.osu.commands.GetCertData;
-import com.android.hotspot2.osu.commands.MOData;
-import com.android.hotspot2.osu.service.RedirectListener;
-import com.android.hotspot2.pps.Credential;
-import com.android.hotspot2.pps.HomeSP;
-import com.android.hotspot2.pps.UpdateInfo;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.security.GeneralSecurityException;
-import java.security.KeyStore;
-import java.security.PrivateKey;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-import javax.net.ssl.KeyManager;
-
-public class OSUClient {
- private static final String TAG = "OSUCLT";
-
- private final OSUInfo mOSUInfo;
- private final URL mURL;
- private final KeyStore mKeyStore;
- private final Context mContext;
- private volatile HTTPHandler mHTTPHandler;
- private volatile RedirectListener mRedirectListener;
-
- public OSUClient(OSUInfo osuInfo, KeyStore ks, Context context) throws MalformedURLException {
- mOSUInfo = osuInfo;
- mURL = new URL(osuInfo.getOSUProvider().getOSUServer());
- mKeyStore = ks;
- mContext = context;
- }
-
- public OSUClient(String osu, KeyStore ks, Context context) throws MalformedURLException {
- mOSUInfo = null;
- mURL = new URL(osu);
- mKeyStore = ks;
- mContext = context;
- }
-
- public OSUInfo getOSUInfo() {
- return mOSUInfo;
- }
-
- public void provision(PlatformAdapter platformAdapter, Network network, KeyManager km)
- throws IOException, GeneralSecurityException {
- try (HTTPHandler httpHandler = new HTTPHandler(StandardCharsets.UTF_8,
- OSUSocketFactory.getSocketFactory(mKeyStore, null,
- OSUFlowManager.FlowType.Provisioning, network, mURL, km, true))) {
-
- mHTTPHandler = httpHandler;
-
- SPVerifier spVerifier = new SPVerifier(mOSUInfo);
- spVerifier.verify(httpHandler.getOSUCertificate(mURL));
-
- URL redirectURL = prepareUserInput(platformAdapter,
- mOSUInfo.getName(Locale.getDefault()));
- OMADMAdapter omadmAdapter = getOMADMAdapter();
-
- String regRequest = SOAPBuilder.buildPostDevDataResponse(RequestReason.SubRegistration,
- null,
- redirectURL.toString(),
- omadmAdapter.getMO(OMAConstants.DevInfoURN),
- omadmAdapter.getMO(OMAConstants.DevDetailURN));
- Log.d(TAG, "Registration request: " + regRequest);
- OSUResponse osuResponse = httpHandler.exchangeSOAP(mURL, regRequest);
-
- Log.d(TAG, "Response: " + osuResponse);
- if (osuResponse.getMessageType() != OSUMessageType.PostDevData) {
- throw new IOException("Expected a PostDevDataResponse");
- }
- PostDevDataResponse regResponse = (PostDevDataResponse) osuResponse;
- String sessionID = regResponse.getSessionID();
- if (regResponse.getExecCommand() == ExecCommand.UseClientCertTLS) {
- ClientCertInfo ccInfo = (ClientCertInfo) regResponse.getCommandData();
- if (ccInfo.doesAcceptMfgCerts()) {
- throw new IOException("Mfg certs are not supported in Android");
- } else if (ccInfo.doesAcceptProviderCerts()) {
- ((WiFiKeyManager) km).enableClientAuth(ccInfo.getIssuerNames());
- httpHandler.renegotiate(null, null);
- } else {
- throw new IOException("Neither manufacturer nor provider cert specified");
- }
- regRequest = SOAPBuilder.buildPostDevDataResponse(RequestReason.SubRegistration,
- sessionID,
- redirectURL.toString(),
- omadmAdapter.getMO(OMAConstants.DevInfoURN),
- omadmAdapter.getMO(OMAConstants.DevDetailURN));
-
- osuResponse = httpHandler.exchangeSOAP(mURL, regRequest);
- if (osuResponse.getMessageType() != OSUMessageType.PostDevData) {
- throw new IOException("Expected a PostDevDataResponse");
- }
- regResponse = (PostDevDataResponse) osuResponse;
- }
-
- if (regResponse.getExecCommand() != ExecCommand.Browser) {
- throw new IOException("Expected a launchBrowser command");
- }
- Log.d(TAG, "Exec: " + regResponse.getExecCommand() + ", for '" +
- regResponse.getCommandData() + "'");
-
- if (!osuResponse.getSessionID().equals(sessionID)) {
- throw new IOException("Mismatching session IDs");
- }
- String webURL = ((BrowserURI) regResponse.getCommandData()).getURI();
-
- if (webURL == null) {
- throw new IOException("No web-url");
- } else if (!webURL.contains(sessionID)) {
- throw new IOException("Bad or missing session ID in webURL");
- }
-
- if (!startUserInput(new URL(webURL), network)) {
- throw new IOException("User session failed");
- }
-
- Log.d(TAG, " -- Sending user input complete:");
- String userComplete = SOAPBuilder.buildPostDevDataResponse(RequestReason.InputComplete,
- sessionID, null,
- omadmAdapter.getMO(OMAConstants.DevInfoURN),
- omadmAdapter.getMO(OMAConstants.DevDetailURN));
- OSUResponse moResponse1 = httpHandler.exchangeSOAP(mURL, userComplete);
- if (moResponse1.getMessageType() != OSUMessageType.PostDevData) {
- throw new IOException("Bad user input complete response: " + moResponse1);
- }
- PostDevDataResponse provResponse = (PostDevDataResponse) moResponse1;
- GetCertData estData = checkResponse(provResponse);
-
- Map<OSUCertType, List<X509Certificate>> certs = new HashMap<>();
- PrivateKey clientKey = null;
-
- MOData moData;
- if (estData == null) {
- moData = (MOData) provResponse.getCommandData();
- } else {
- try (ESTHandler estHandler = new ESTHandler((GetCertData) provResponse.
- getCommandData(), network, getOMADMAdapter(),
- km, mKeyStore, null, OSUFlowManager.FlowType.Provisioning)) {
- estHandler.execute(false);
- certs.put(OSUCertType.CA, estHandler.getCACerts());
- certs.put(OSUCertType.Client, estHandler.getClientCerts());
- clientKey = estHandler.getClientKey();
- }
-
- Log.d(TAG, " -- Sending provisioning cert enrollment complete:");
- String certComplete =
- SOAPBuilder.buildPostDevDataResponse(RequestReason.CertEnrollmentComplete,
- sessionID, null,
- omadmAdapter.getMO(OMAConstants.DevInfoURN),
- omadmAdapter.getMO(OMAConstants.DevDetailURN));
- OSUResponse moResponse2 = httpHandler.exchangeSOAP(mURL, certComplete);
- if (moResponse2.getMessageType() != OSUMessageType.PostDevData) {
- throw new IOException("Bad cert enrollment complete response: " + moResponse2);
- }
- PostDevDataResponse provComplete = (PostDevDataResponse) moResponse2;
- if (provComplete.getStatus() != OSUStatus.ProvComplete ||
- provComplete.getOSUCommand() != OSUCommandID.AddMO) {
- throw new IOException("Expected addMO: " + provComplete);
- }
- moData = (MOData) provComplete.getCommandData();
- }
-
- // !!! How can an ExchangeComplete be sent w/o knowing the fate of the certs???
- String updateResponse = SOAPBuilder.buildUpdateResponse(sessionID, null);
- Log.d(TAG, " -- Sending updateResponse:");
- OSUResponse exComplete = httpHandler.exchangeSOAP(mURL, updateResponse);
- Log.d(TAG, "exComplete response: " + exComplete);
- if (exComplete.getMessageType() != OSUMessageType.ExchangeComplete) {
- throw new IOException("Expected ExchangeComplete: " + exComplete);
- } else if (exComplete.getStatus() != OSUStatus.ExchangeComplete) {
- throw new IOException("Bad ExchangeComplete status: " + exComplete);
- }
-
- retrieveCerts(moData.getMOTree().getRoot(), certs, network, km, mKeyStore);
- platformAdapter.provisioningComplete(mOSUInfo, moData, certs, clientKey, network);
- }
- }
-
- public void remediate(PlatformAdapter platformAdapter, Network network, KeyManager km,
- HomeSP homeSP, OSUFlowManager.FlowType flowType)
- throws IOException, GeneralSecurityException {
- try (HTTPHandler httpHandler = createHandler(network, homeSP, km, flowType)) {
-
- mHTTPHandler = httpHandler;
-
- URL redirectURL = prepareUserInput(platformAdapter, homeSP.getFriendlyName());
- OMADMAdapter omadmAdapter = getOMADMAdapter();
-
- String regRequest = SOAPBuilder.buildPostDevDataResponse(RequestReason.SubRemediation,
- null,
- redirectURL.toString(),
- omadmAdapter.getMO(OMAConstants.DevInfoURN),
- omadmAdapter.getMO(OMAConstants.DevDetailURN));
-
- OSUResponse serverResponse = httpHandler.exchangeSOAP(mURL, regRequest);
- if (serverResponse.getMessageType() != OSUMessageType.PostDevData) {
- throw new IOException("Expected a PostDevDataResponse");
- }
- String sessionID = serverResponse.getSessionID();
-
- PostDevDataResponse pddResponse = (PostDevDataResponse) serverResponse;
- Log.d(TAG, "Remediation response: " + pddResponse);
-
- Map<OSUCertType, List<X509Certificate>> certs = null;
- PrivateKey clientKey = null;
-
- if (pddResponse.getStatus() != OSUStatus.RemediationComplete) {
- if (pddResponse.getExecCommand() == ExecCommand.UploadMO) {
- String ulMessage = SOAPBuilder.buildPostDevDataResponse(RequestReason.MOUpload,
- null,
- redirectURL.toString(),
- omadmAdapter.getMO(OMAConstants.DevInfoURN),
- omadmAdapter.getMO(OMAConstants.DevDetailURN),
- platformAdapter.getMOTree(homeSP));
-
- Log.d(TAG, "Upload MO: " + ulMessage);
-
- OSUResponse ulResponse = httpHandler.exchangeSOAP(mURL, ulMessage);
- if (ulResponse.getMessageType() != OSUMessageType.PostDevData) {
- throw new IOException("Expected a PostDevDataResponse to MOUpload");
- }
- pddResponse = (PostDevDataResponse) ulResponse;
- }
-
- if (pddResponse.getExecCommand() == ExecCommand.Browser) {
- if (flowType == OSUFlowManager.FlowType.Policy) {
- throw new IOException("Browser launch requested in policy flow");
- }
- String webURL = ((BrowserURI) pddResponse.getCommandData()).getURI();
-
- if (webURL == null) {
- throw new IOException("No web-url");
- } else if (!webURL.contains(sessionID)) {
- throw new IOException("Bad or missing session ID in webURL");
- }
-
- if (!startUserInput(new URL(webURL), network)) {
- throw new IOException("User session failed");
- }
-
- Log.d(TAG, " -- Sending user input complete:");
- String userComplete =
- SOAPBuilder.buildPostDevDataResponse(RequestReason.InputComplete,
- sessionID, null,
- omadmAdapter.getMO(OMAConstants.DevInfoURN),
- omadmAdapter.getMO(OMAConstants.DevDetailURN));
-
- OSUResponse udResponse = httpHandler.exchangeSOAP(mURL, userComplete);
- if (udResponse.getMessageType() != OSUMessageType.PostDevData) {
- throw new IOException("Bad user input complete response: " + udResponse);
- }
- pddResponse = (PostDevDataResponse) udResponse;
- } else if (pddResponse.getExecCommand() == ExecCommand.GetCert) {
- certs = new HashMap<>();
- try (ESTHandler estHandler = new ESTHandler((GetCertData) pddResponse.
- getCommandData(), network, getOMADMAdapter(),
- km, mKeyStore, homeSP, flowType)) {
- estHandler.execute(true);
- certs.put(OSUCertType.CA, estHandler.getCACerts());
- certs.put(OSUCertType.Client, estHandler.getClientCerts());
- clientKey = estHandler.getClientKey();
- }
-
- if (httpHandler.isHTTPAuthPerformed()) { // 8.4.3.6
- httpHandler.renegotiate(certs, clientKey);
- }
-
- Log.d(TAG, " -- Sending remediation cert enrollment complete:");
- // 8.4.3.5 in the spec actually prescribes that an update URI is sent here,
- // but there is no remediation flow that defines user interaction after EST
- // so for now a null is passed.
- String certComplete =
- SOAPBuilder
- .buildPostDevDataResponse(RequestReason.CertEnrollmentComplete,
- sessionID, null,
- omadmAdapter.getMO(OMAConstants.DevInfoURN),
- omadmAdapter.getMO(OMAConstants.DevDetailURN));
- OSUResponse ceResponse = httpHandler.exchangeSOAP(mURL, certComplete);
- if (ceResponse.getMessageType() != OSUMessageType.PostDevData) {
- throw new IOException("Bad cert enrollment complete response: "
- + ceResponse);
- }
- pddResponse = (PostDevDataResponse) ceResponse;
- } else {
- throw new IOException("Unexpected command: " + pddResponse.getExecCommand());
- }
- }
-
- if (pddResponse.getStatus() != OSUStatus.RemediationComplete) {
- throw new IOException("Expected a PostDevDataResponse to MOUpload");
- }
-
- Log.d(TAG, "Remediation response: " + pddResponse);
-
- List<MOData> mods = new ArrayList<>();
- for (OSUCommand command : pddResponse.getCommands()) {
- if (command.getOSUCommand() == OSUCommandID.UpdateNode) {
- mods.add((MOData) command.getCommandData());
- } else if (command.getOSUCommand() != OSUCommandID.NoMOUpdate) {
- throw new IOException("Unexpected OSU response: " + command);
- }
- }
-
- // 1. Machine remediation: Remediation complete + replace node
- // 2a. User remediation with upload: ExecCommand.UploadMO
- // 2b. User remediation without upload: ExecCommand.Browser
- // 3. User remediation only: -> sppPostDevData user input complete
- //
- // 4. Update node
- // 5. -> Update response
- // 6. Exchange complete
-
- OSUError error = null;
-
- String updateResponse = SOAPBuilder.buildUpdateResponse(sessionID, error);
- Log.d(TAG, " -- Sending updateResponse:");
- OSUResponse exComplete = httpHandler.exchangeSOAP(mURL, updateResponse);
- Log.d(TAG, "exComplete response: " + exComplete);
- if (exComplete.getMessageType() != OSUMessageType.ExchangeComplete) {
- throw new IOException("Expected ExchangeComplete: " + exComplete);
- } else if (exComplete.getStatus() != OSUStatus.ExchangeComplete) {
- throw new IOException("Bad ExchangeComplete status: " + exComplete);
- }
-
- // There's a chicken and egg here: If the config is saved before sending update complete
- // the network is lost and the remediation flow fails.
- try {
- platformAdapter.remediationComplete(homeSP, mods, certs, clientKey,
- flowType == OSUFlowManager.FlowType.Policy);
- } catch (IOException | GeneralSecurityException e) {
- platformAdapter.provisioningFailed(homeSP.getFriendlyName(), e.getMessage());
- error = OSUError.CommandFailed;
- }
- }
- }
-
- private OMADMAdapter getOMADMAdapter() {
- return OMADMAdapter.getInstance(mContext);
- }
-
- private URL prepareUserInput(PlatformAdapter platformAdapter, String spName)
- throws IOException {
- mRedirectListener = new RedirectListener(platformAdapter, spName);
- return mRedirectListener.getURL();
- }
-
- private boolean startUserInput(URL target, Network network)
- throws IOException {
- mRedirectListener.startService();
-
- Intent intent = new Intent(mContext, OSUWebView.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.putExtra(OSUWebView.OSU_NETWORK, network);
- intent.putExtra(OSUWebView.OSU_URL, target.toString());
- mContext.startActivity(intent);
-
- return mRedirectListener.waitForUser();
- }
-
- public void close(boolean abort) {
- if (mRedirectListener != null) {
- mRedirectListener.abort();
- mRedirectListener = null;
- }
- if (abort) {
- try {
- mHTTPHandler.close();
- } catch (IOException ioe) {
- /**/
- }
- }
- }
-
- private HTTPHandler createHandler(Network network, HomeSP homeSP, KeyManager km,
- OSUFlowManager.FlowType flowType)
- throws GeneralSecurityException, IOException {
- Credential credential = homeSP.getCredential();
-
- Log.d(TAG, "Credential method " + credential.getEAPMethod().getEAPMethodID());
- switch (credential.getEAPMethod().getEAPMethodID()) {
- case EAP_TTLS:
- String user;
- byte[] password;
- UpdateInfo subscriptionUpdate;
- if (flowType == OSUFlowManager.FlowType.Policy) {
- subscriptionUpdate = homeSP.getPolicy() != null ?
- homeSP.getPolicy().getPolicyUpdate() : null;
- } else {
- subscriptionUpdate = homeSP.getSubscriptionUpdate();
- }
- if (subscriptionUpdate != null && subscriptionUpdate.getUsername() != null) {
- user = subscriptionUpdate.getUsername();
- password = subscriptionUpdate.getPassword() != null ?
- subscriptionUpdate.getPassword().getBytes(StandardCharsets.UTF_8) :
- new byte[0];
- } else {
- user = credential.getUserName();
- password = credential.getPassword().getBytes(StandardCharsets.UTF_8);
- }
- return new HTTPHandler(StandardCharsets.UTF_8,
- OSUSocketFactory.getSocketFactory(mKeyStore, homeSP, flowType, network,
- mURL, km, true), user, password);
- case EAP_TLS:
- return new HTTPHandler(StandardCharsets.UTF_8,
- OSUSocketFactory.getSocketFactory(mKeyStore, homeSP, flowType, network,
- mURL, km, true));
- default:
- throw new IOException("Cannot remediate account with " +
- credential.getEAPMethod().getEAPMethodID());
- }
- }
-
- private static GetCertData checkResponse(PostDevDataResponse response) throws IOException {
- if (response.getStatus() == OSUStatus.ProvComplete &&
- response.getOSUCommand() == OSUCommandID.AddMO) {
- return null;
- }
-
- if (response.getOSUCommand() == OSUCommandID.Exec &&
- response.getExecCommand() == ExecCommand.GetCert) {
- return (GetCertData) response.getCommandData();
- } else {
- throw new IOException("Unexpected command: " + response);
- }
- }
-
- private static final String[] AAACertPath =
- {"PerProviderSubscription", "?", "AAAServerTrustRoot", "*", "CertURL"};
- private static final String[] RemdCertPath =
- {"PerProviderSubscription", "?", "SubscriptionUpdate", "TrustRoot", "CertURL"};
- private static final String[] PolicyCertPath =
- {"PerProviderSubscription", "?", "Policy", "PolicyUpdate", "TrustRoot", "CertURL"};
-
- private static void retrieveCerts(OMANode ppsRoot,
- Map<OSUCertType, List<X509Certificate>> certs,
- Network network, KeyManager km, KeyStore ks)
- throws GeneralSecurityException, IOException {
-
- List<X509Certificate> aaaCerts = getCerts(ppsRoot, AAACertPath, network, km, ks);
- certs.put(OSUCertType.AAA, aaaCerts);
- certs.put(OSUCertType.Remediation, getCerts(ppsRoot, RemdCertPath, network, km, ks));
- certs.put(OSUCertType.Policy, getCerts(ppsRoot, PolicyCertPath, network, km, ks));
- }
-
- private static List<X509Certificate> getCerts(OMANode ppsRoot, String[] path, Network network,
- KeyManager km, KeyStore ks)
- throws GeneralSecurityException, IOException {
- List<String> urls = new ArrayList<>();
- getCertURLs(ppsRoot, Arrays.asList(path).iterator(), urls);
- Log.d(TAG, Arrays.toString(path) + ": " + urls);
-
- List<X509Certificate> certs = new ArrayList<>(urls.size());
- CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
- for (String urlString : urls) {
- URL url = new URL(urlString);
- HTTPHandler httpHandler = new HTTPHandler(StandardCharsets.UTF_8,
- OSUSocketFactory.getSocketFactory(ks, null,
- OSUFlowManager.FlowType.Provisioning, network, url, km, false));
-
- certs.add((X509Certificate) certFactory.generateCertificate(httpHandler.doGet(url)));
- }
- return certs;
- }
-
- private static void getCertURLs(OMANode root, Iterator<String> path, List<String> urls)
- throws IOException {
-
- String name = path.next();
- // Log.d(TAG, "Pulling '" + name + "' out of '" + root.getName() + "'");
- Collection<OMANode> nodes = null;
- switch (name) {
- case "?":
- for (OMANode node : root.getChildren()) {
- if (!node.isLeaf()) {
- nodes = Collections.singletonList(node);
- break;
- }
- }
- break;
- case "*":
- nodes = root.getChildren();
- break;
- default:
- nodes = Collections.singletonList(root.getChild(name));
- break;
- }
-
- if (nodes == null) {
- throw new IllegalArgumentException("No matching node in " + root.getName()
- + " for " + name);
- }
-
- for (OMANode node : nodes) {
- if (path.hasNext()) {
- getCertURLs(node, path, urls);
- } else {
- urls.add(node.getValue());
- }
- }
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/OSUCommand.java b/packages/Osu/src/com/android/hotspot2/osu/OSUCommand.java
deleted file mode 100644
index 4730377c5779..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/OSUCommand.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package com.android.hotspot2.osu;
-
-import com.android.hotspot2.omadm.OMAException;
-import com.android.hotspot2.omadm.XMLNode;
-import com.android.hotspot2.osu.commands.BrowserURI;
-import com.android.hotspot2.osu.commands.ClientCertInfo;
-import com.android.hotspot2.osu.commands.GetCertData;
-import com.android.hotspot2.osu.commands.MOData;
-import com.android.hotspot2.osu.commands.MOURN;
-import com.android.hotspot2.osu.commands.OSUCommandData;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class OSUCommand {
- private final OSUCommandID mOSUCommand;
- private final ExecCommand mExecCommand;
- private final OSUCommandData mCommandData;
-
- private static final Map<String, OSUCommandID> sCommands = new HashMap<>();
- private static final Map<String, ExecCommand> sExecs = new HashMap<>();
-
- static {
- sCommands.put("exec", OSUCommandID.Exec);
- sCommands.put("addmo", OSUCommandID.AddMO);
- sCommands.put("updatenode", OSUCommandID.UpdateNode); // Multi
- sCommands.put("nomoupdate", OSUCommandID.NoMOUpdate);
-
- sExecs.put("launchbrowsertouri", ExecCommand.Browser);
- sExecs.put("getcertificate", ExecCommand.GetCert);
- sExecs.put("useclientcerttls", ExecCommand.UseClientCertTLS);
- sExecs.put("uploadmo", ExecCommand.UploadMO);
- }
-
- public OSUCommand(XMLNode child) throws OMAException {
- mOSUCommand = sCommands.get(child.getStrippedTag());
-
- switch (mOSUCommand) {
- case Exec:
- /*
- * Receipt of this element by a mobile device causes the following command
- * to be executed.
- */
- child = child.getSoleChild();
- mExecCommand = sExecs.get(child.getStrippedTag());
- if (mExecCommand == null) {
- throw new OMAException("Unrecognized exec command: " + child.getStrippedTag());
- }
- switch (mExecCommand) {
- case Browser:
- /*
- * When the mobile device receives this command, it launches its default
- * browser to the URI contained in this element. The URI must use HTTPS as
- * the protocol and must contain an FQDN.
- */
- mCommandData = new BrowserURI(child);
- break;
- case GetCert:
- mCommandData = new GetCertData(child);
- break;
- case UploadMO:
- mCommandData = new MOURN(child);
- break;
- case UseClientCertTLS:
- /*
- * Command to mobile to re-negotiate the TLS connection using a client
- * certificate of the accepted type or Issuer to authenticate with the
- * Subscription server.
- */
- mCommandData = new ClientCertInfo(child);
- break;
- default:
- mCommandData = null;
- break;
- }
- break;
- case AddMO:
- /*
- * This command causes an management object in the mobile devices management tree
- * at the specified location to be added.
- * If there is already a management object at that location, the object is replaced.
- */
- mExecCommand = null;
- mCommandData = new MOData(child);
- break;
- case UpdateNode:
- /*
- * This command causes the update of an interior node and its child nodes (if any)
- * at the location specified in the management tree URI attribute. The content of
- * this element is the MO node XML.
- */
- mExecCommand = null;
- mCommandData = new MOData(child);
- break;
- case NoMOUpdate:
- /*
- * This response is used when there is no command to be executed nor update of
- * any MO required.
- */
- mExecCommand = null;
- mCommandData = null;
- break;
- default:
- mExecCommand = null;
- mCommandData = null;
- break;
- }
- }
-
- public OSUCommandID getOSUCommand() {
- return mOSUCommand;
- }
-
- public ExecCommand getExecCommand() {
- return mExecCommand;
- }
-
- public OSUCommandData getCommandData() {
- return mCommandData;
- }
-
- @Override
- public String toString() {
- return "OSUCommand{" +
- "OSUCommand=" + mOSUCommand +
- ", execCommand=" + mExecCommand +
- ", commandData=" + mCommandData +
- '}';
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/OSUCommandID.java b/packages/Osu/src/com/android/hotspot2/osu/OSUCommandID.java
deleted file mode 100644
index eca953ff97ec..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/OSUCommandID.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.android.hotspot2.osu;
-
-public enum OSUCommandID {
- Exec, AddMO, UpdateNode, NoMOUpdate
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/OSUError.java b/packages/Osu/src/com/android/hotspot2/osu/OSUError.java
deleted file mode 100644
index 2fa7de07fd80..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/OSUError.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.android.hotspot2.osu;
-
-public enum OSUError {
- SPPversionNotSupported,
- MOsNotSupported,
- CredentialsFailure,
- RemediationFailure,
- ProvisioningFailed,
- ExistingCertificate,
- CookieInvalid,
- WebSessionID,
- PermissionDenied,
- CommandFailed,
- MOaddOrUpdateFailed,
- DeviceFull,
- BadTreeURI,
- TooLarge,
- CommandNotAllowed,
- UserAborted,
- NotFound,
- Other
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/OSUFlowManager.java b/packages/Osu/src/com/android/hotspot2/osu/OSUFlowManager.java
deleted file mode 100644
index 0123d69881df..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/OSUFlowManager.java
+++ /dev/null
@@ -1,392 +0,0 @@
-package com.android.hotspot2.osu;
-
-import android.content.Context;
-import android.content.Intent;
-import android.net.Network;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
-import android.os.SystemClock;
-import android.util.Log;
-
-import com.android.hotspot2.Utils;
-import com.android.hotspot2.flow.FlowService;
-import com.android.hotspot2.flow.OSUInfo;
-import com.android.hotspot2.flow.PlatformAdapter;
-import com.android.hotspot2.pps.HomeSP;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.util.Iterator;
-import java.util.LinkedList;
-
-import javax.net.ssl.KeyManager;
-
-public class OSUFlowManager {
- private static final boolean MATCH_BSSID = false;
- private static final long WAIT_QUANTA = 10000L;
- private static final long WAIT_TIMEOUT = 1800000L;
-
- private final Context mContext;
- private final LinkedList<OSUFlow> mQueue;
- private FlowWorker mWorker;
- private OSUFlow mCurrent;
-
- public OSUFlowManager(Context context) {
- mContext = context;
- mQueue = new LinkedList<>();
- }
-
- public enum FlowType {Provisioning, Remediation, Policy}
-
- public static class OSUFlow implements Runnable {
- private final OSUClient mOSUClient;
- private final PlatformAdapter mPlatformAdapter;
- private final HomeSP mHomeSP;
- private final String mSpName;
- private final FlowType mFlowType;
- private final KeyManager mKeyManager;
- private final Object mNetworkLock = new Object();
- private final Network mNetwork;
- private Network mResultNetwork;
- private boolean mNetworkCreated;
- private int mWifiNetworkId;
- private volatile long mLaunchTime;
- private volatile boolean mAborted;
-
- /**
- * A policy flow.
- * @param osuInfo The OSU information for the flow (SSID, BSSID, URL)
- * @param platformAdapter the platform adapter
- * @param km A key manager for TLS
- * @throws MalformedURLException
- */
- public OSUFlow(OSUInfo osuInfo, PlatformAdapter platformAdapter, KeyManager km)
- throws MalformedURLException {
-
- mWifiNetworkId = -1;
- mNetwork = null;
- mOSUClient = new OSUClient(osuInfo,
- platformAdapter.getKeyStore(), platformAdapter.getContext());
- mPlatformAdapter = platformAdapter;
- mHomeSP = null;
- mSpName = osuInfo.getName(OSUManager.LOCALE);
- mFlowType = FlowType.Provisioning;
- mKeyManager = km;
- }
-
- /**
- * A Remediation flow for credential or policy provisioning.
- * @param network The network to use, only set for timed provisioning
- * @param osuURL The URL to connect to.
- * @param platformAdapter the platform adapter
- * @param km A key manager for TLS
- * @param homeSP The Home SP to which this remediation flow pertains.
- * @param flowType Remediation or Policy
- * @throws MalformedURLException
- */
- public OSUFlow(Network network, String osuURL,
- PlatformAdapter platformAdapter, KeyManager km, HomeSP homeSP,
- FlowType flowType) throws MalformedURLException {
-
- mNetwork = network;
- mWifiNetworkId = network.netId;
- mOSUClient = new OSUClient(osuURL,
- platformAdapter.getKeyStore(), platformAdapter.getContext());
- mPlatformAdapter = platformAdapter;
- mHomeSP = homeSP;
- mSpName = homeSP.getFriendlyName();
- mFlowType = flowType;
- mKeyManager = km;
- }
-
- private boolean deleteNetwork(OSUFlow next) {
- synchronized (mNetworkLock) {
- if (!mNetworkCreated) {
- return false;
- } else if (next.getFlowType() != FlowType.Provisioning) {
- return true;
- }
- OSUInfo thisInfo = mOSUClient.getOSUInfo();
- OSUInfo thatInfo = next.mOSUClient.getOSUInfo();
- if (thisInfo.getOsuSsid().equals(thatInfo.getOsuSsid())
- && thisInfo.getOSUBssid() == thatInfo.getOSUBssid()) {
- // Reuse the OSU network from previous and carry forward the creation fact.
- mNetworkCreated = true;
- return false;
- } else {
- return true;
- }
- }
- }
-
- private Network connect() throws IOException {
- Network network = networkMatch();
-
- synchronized (mNetworkLock) {
- mResultNetwork = network;
- if (mResultNetwork != null) {
- return mResultNetwork;
- }
- }
-
- Log.d(OSUManager.TAG, "No network match for " + toString());
-
- int osuNetworkId = -1;
- boolean created = false;
-
- if (mFlowType == FlowType.Provisioning) {
- osuNetworkId = mPlatformAdapter.connect(mOSUClient.getOSUInfo());
- created = true;
- }
-
- synchronized (mNetworkLock) {
- mNetworkCreated = created;
- if (created) {
- mWifiNetworkId = osuNetworkId;
- }
- Log.d(OSUManager.TAG, String.format("%s waiting for %snet ID %d",
- toString(), created ? "created " : "existing ", osuNetworkId));
-
- while (mResultNetwork == null && !mAborted) {
- try {
- mNetworkLock.wait();
- } catch (InterruptedException ie) {
- throw new IOException("Interrupted");
- }
- }
- if (mAborted) {
- throw new IOException("Aborted");
- }
- Utils.delay(500L);
- }
- return mResultNetwork;
- }
-
- private Network networkMatch() {
- if (mFlowType == FlowType.Provisioning) {
- OSUInfo match = mOSUClient.getOSUInfo();
- WifiConfiguration config = mPlatformAdapter.getActiveWifiConfig();
- if (config != null && bssidMatch(match, mPlatformAdapter)
- && Utils.decodeSsid(config.SSID).equals(match.getOsuSsid())) {
- synchronized (mNetworkLock) {
- mWifiNetworkId = config.networkId;
- }
- return mPlatformAdapter.getCurrentNetwork();
- }
- } else {
- WifiConfiguration config = mPlatformAdapter.getActiveWifiConfig();
- synchronized (mNetworkLock) {
- mWifiNetworkId = config != null ? config.networkId : -1;
- }
- return mNetwork;
- }
- return null;
- }
-
- private void networkChange() {
- WifiInfo connectionInfo = mPlatformAdapter.getConnectionInfo();
- if (connectionInfo == null) {
- return;
- }
- Network network = mPlatformAdapter.getCurrentNetwork();
- Log.d(OSUManager.TAG, "New network " + network
- + ", current OSU " + mOSUClient.getOSUInfo() +
- ", addr " + Utils.toIpString(connectionInfo.getIpAddress()));
-
- synchronized (mNetworkLock) {
- if (mResultNetwork == null && network != null && connectionInfo.getIpAddress() != 0
- && connectionInfo.getNetworkId() == mWifiNetworkId) {
- mResultNetwork = network;
- mNetworkLock.notifyAll();
- }
- }
- }
-
- public boolean createdNetwork() {
- synchronized (mNetworkLock) {
- return mNetworkCreated;
- }
- }
-
- public FlowType getFlowType() {
- return mFlowType;
- }
-
- public PlatformAdapter getPlatformAdapter() {
- return mPlatformAdapter;
- }
-
- private void setLaunchTime() {
- mLaunchTime = SystemClock.currentThreadTimeMillis();
- }
-
- public long getLaunchTime() {
- return mLaunchTime;
- }
-
- private int getWifiNetworkId() {
- synchronized (mNetworkLock) {
- return mWifiNetworkId;
- }
- }
-
- @Override
- public void run() {
- try {
- Network network = connect();
- Log.d(OSUManager.TAG, "OSU SSID Associated at " + network);
-
- if (mFlowType == FlowType.Provisioning) {
- mOSUClient.provision(mPlatformAdapter, network, mKeyManager);
- } else {
- mOSUClient.remediate(mPlatformAdapter, network,
- mKeyManager, mHomeSP, mFlowType);
- }
- } catch (Throwable t) {
- if (mAborted) {
- Log.d(OSUManager.TAG, "OSU flow aborted: " + t, t);
- } else {
- Log.w(OSUManager.TAG, "OSU flow failed: " + t, t);
- mPlatformAdapter.provisioningFailed(mSpName, t.getMessage());
- }
- } finally {
- if (!mAborted) {
- mOSUClient.close(false);
- }
- }
- }
-
- public void abort() {
- synchronized (mNetworkLock) {
- mAborted = true;
- mNetworkLock.notifyAll();
- }
- // Sockets cannot be closed on the main thread...
- // TODO: Might want to change this to a handler.
- new Thread() {
- @Override
- public void run() {
- try {
- mOSUClient.close(true);
- } catch (Throwable t) {
- Log.d(OSUManager.TAG, "Exception aborting " + toString());
- }
- }
- }.start();
- }
-
- @Override
- public String toString() {
- return mFlowType + " for " + mSpName;
- }
- }
-
- private class FlowWorker extends Thread {
- private final PlatformAdapter mPlatformAdapter;
-
- private FlowWorker(PlatformAdapter platformAdapter) {
- mPlatformAdapter = platformAdapter;
- }
-
- @Override
- public void run() {
- for (; ; ) {
- synchronized (mQueue) {
- if (mCurrent != null && mCurrent.createdNetwork()
- && (mQueue.isEmpty() || mCurrent.deleteNetwork(mQueue.getLast()))) {
- mPlatformAdapter.deleteNetwork(mCurrent.getWifiNetworkId());
- }
-
- mCurrent = null;
- while (mQueue.isEmpty()) {
- try {
- mQueue.wait(WAIT_QUANTA);
- } catch (InterruptedException ie) {
- return;
- }
- if (mQueue.isEmpty()) {
- // Bail out on time out
- Log.d(OSUManager.TAG, "Flow worker terminating.");
- mWorker = null;
- mContext.stopService(new Intent(mContext, FlowService.class));
- return;
- }
- }
- mCurrent = mQueue.removeLast();
- mCurrent.setLaunchTime();
- }
- Log.d(OSUManager.TAG, "Starting " + mCurrent);
- mCurrent.run();
- Log.d(OSUManager.TAG, "Exiting " + mCurrent);
- }
- }
- }
-
- /*
- * Provisioning: Wait until there is an active WiFi info and the active WiFi config
- * matches SSID and optionally BSSID.
- * WNM Remediation: Wait until the active WiFi info matches BSSID.
- * Timed remediation: The network is given (may be cellular).
- */
-
- public void appendFlow(OSUFlow flow) {
- synchronized (mQueue) {
- if (mCurrent != null &&
- SystemClock.currentThreadTimeMillis()
- - mCurrent.getLaunchTime() >= WAIT_TIMEOUT) {
- Log.d(OSUManager.TAG, "Aborting stale OSU flow " + mCurrent);
- mCurrent.abort();
- mCurrent = null;
- }
-
- if (flow.getFlowType() == FlowType.Provisioning) {
- // Kill any outstanding provisioning flows.
- Iterator<OSUFlow> flows = mQueue.iterator();
- while (flows.hasNext()) {
- if (flows.next().getFlowType() == FlowType.Provisioning) {
- flows.remove();
- }
- }
-
- if (mCurrent != null
- && mCurrent.getFlowType() == FlowType.Provisioning) {
- Log.d(OSUManager.TAG, "Aborting current provisioning flow " + mCurrent);
- mCurrent.abort();
- mCurrent = null;
- }
-
- mQueue.addLast(flow);
- } else {
- mQueue.addFirst(flow);
- }
-
- if (mWorker == null) {
- // TODO: Might want to change this to a handler.
- mWorker = new FlowWorker(flow.getPlatformAdapter());
- mWorker.start();
- }
-
- mQueue.notifyAll();
- }
- }
-
- public void networkChange() {
- OSUFlow pending;
- synchronized (mQueue) {
- pending = mCurrent;
- }
- Log.d(OSUManager.TAG, "Network change, current flow: " + pending);
- if (pending != null) {
- pending.networkChange();
- }
- }
-
- private static boolean bssidMatch(OSUInfo osuInfo, PlatformAdapter platformAdapter) {
- if (MATCH_BSSID) {
- WifiInfo wifiInfo = platformAdapter.getConnectionInfo();
- return wifiInfo != null && Utils.parseMac(wifiInfo.getBSSID()) == osuInfo.getOSUBssid();
- } else {
- return true;
- }
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/OSUListener.java b/packages/Osu/src/com/android/hotspot2/osu/OSUListener.java
deleted file mode 100644
index 91976201f8e5..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/OSUListener.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.android.hotspot2.osu;
-
-public interface OSUListener {
- public void osuNotification(int count);
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/OSUManager.java b/packages/Osu/src/com/android/hotspot2/osu/OSUManager.java
deleted file mode 100644
index 24cd10f1e583..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/OSUManager.java
+++ /dev/null
@@ -1,264 +0,0 @@
-package com.android.hotspot2.osu;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.anqp.HSIconFileElement;
-import com.android.anqp.OSUProvider;
-import com.android.hotspot2.AppBridge;
-import com.android.hotspot2.PasspointMatch;
-import com.android.hotspot2.Utils;
-import com.android.hotspot2.app.OSUData;
-import com.android.hotspot2.flow.FlowService;
-import com.android.hotspot2.flow.OSUInfo;
-import com.android.hotspot2.osu.service.RemediationHandler;
-import com.android.hotspot2.flow.IFlowService;
-
-import java.io.File;
-import java.net.MalformedURLException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-
-public class OSUManager {
- public static final String TAG = "OSUMGR";
- public static final boolean R2_MOCK = true;
- private static final String REMEDIATION_FILE = "remediation.state";
-
- // Preferred icon parameters
- public static final Locale LOCALE = java.util.Locale.getDefault();
-
- private final AppBridge mAppBridge;
- private final Context mContext;
- private final IconCache mIconCache;
- private final RemediationHandler mRemediationHandler;
- private final Set<String> mOSUSSIDs = new HashSet<>();
- private final Map<OSUProvider, OSUInfo> mOSUMap = new HashMap<>();
- private final AtomicInteger mOSUSequence = new AtomicInteger();
-
- private final OSUCache mOSUCache;
-
- public OSUManager(Context context) {
- mContext = context;
- mAppBridge = new AppBridge(context);
- mIconCache = new IconCache(this);
- File appFolder = context.getFilesDir();
- mRemediationHandler =
- new RemediationHandler(context, new File(appFolder, REMEDIATION_FILE));
- mOSUCache = new OSUCache();
- }
-
- public Context getContext() {
- return mContext;
- }
-
- public List<OSUData> getAvailableOSUs() {
- synchronized (mOSUMap) {
- List<OSUData> completeOSUs = new ArrayList<>();
- for (OSUInfo osuInfo : mOSUMap.values()) {
- if (osuInfo.getIconStatus() == OSUInfo.IconStatus.Available) {
- completeOSUs.add(new OSUData(osuInfo));
- }
- }
- return completeOSUs;
- }
- }
-
- public void setOSUSelection(int osuID) {
- OSUInfo selection = null;
- for (OSUInfo osuInfo : mOSUMap.values()) {
- if (osuInfo.getOsuID() == osuID &&
- osuInfo.getIconStatus() == OSUInfo.IconStatus.Available) {
- selection = osuInfo;
- break;
- }
- }
-
- Log.d(TAG, "Selected OSU ID " + osuID + ": " + selection);
-
- if (selection == null) {
- return;
- }
-
- final OSUInfo osu = selection;
-
- mContext.bindService(new Intent(mContext, FlowService.class), new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- try {
- IFlowService fs = IFlowService.Stub.asInterface(service);
- fs.provision(osu);
- } catch (RemoteException re) {
- Log.e(OSUManager.TAG, "Caught re: " + re);
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- Log.d(OSUManager.TAG, "Service disconnect: " + name);
- }
- }, Context.BIND_AUTO_CREATE);
- }
-
- public void networkDeleted(final WifiConfiguration configuration) {
- if (configuration.FQDN == null) {
- return;
- }
-
- mRemediationHandler.networkConfigChange();
- mContext.bindService(new Intent(mContext, FlowService.class), new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- try {
- IFlowService fs = IFlowService.Stub.asInterface(service);
- fs.spDeleted(configuration.FQDN);
- } catch (RemoteException re) {
- Log.e(OSUManager.TAG, "Caught re: " + re);
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
-
- }
- }, Context.BIND_AUTO_CREATE);
- }
-
- public void networkConnectChange(WifiInfo newNetwork) {
- mRemediationHandler.newConnection(newNetwork);
- }
-
- public void networkConfigChanged() {
- mRemediationHandler.networkConfigChange();
- }
-
- public void wifiStateChange(boolean on) {
- if (on) {
- return;
- }
-
- // Notify the remediation handler that there are no WiFi networks available.
- // Do NOT turn it off though as remediation, per at least this implementation, can take
- // place over cellular. The subject of remediation over cellular (when restriction is
- // "unrestricted") is not addresses by the WFA spec and direct ask to authors gives no
- // distinct answer one way or the other.
- mRemediationHandler.newConnection(null);
- int current = mOSUMap.size();
- mOSUMap.clear();
- mOSUCache.clearAll();
- mIconCache.tick(true);
- if (current > 0) {
- notifyOSUCount();
- }
- }
-
- public boolean isOSU(String ssid) {
- synchronized (mOSUMap) {
- return mOSUSSIDs.contains(ssid);
- }
- }
-
- public void pushScanResults(Collection<ScanResult> scanResults) {
- Map<OSUProvider, ScanResult> results = mOSUCache.pushScanResults(scanResults);
- if (results != null) {
- updateOSUInfoCache(results);
- }
- mIconCache.tick(false);
- }
-
- private void updateOSUInfoCache(Map<OSUProvider, ScanResult> results) {
- Map<OSUProvider, OSUInfo> osus = new HashMap<>();
- for (Map.Entry<OSUProvider, ScanResult> entry : results.entrySet()) {
- OSUInfo existing = mOSUMap.get(entry.getKey());
- long bssid = Utils.parseMac(entry.getValue().BSSID);
-
- if (existing == null) {
- osus.put(entry.getKey(), new OSUInfo(entry.getValue(), entry.getKey(),
- mOSUSequence.getAndIncrement()));
- } else if (existing.getBSSID() != bssid) {
- HSIconFileElement icon = mIconCache.getIcon(existing);
- if (icon != null && icon.equals(existing.getIconFileElement())) {
- OSUInfo osuInfo = new OSUInfo(entry.getValue(), entry.getKey(),
- existing.getOsuID());
- osuInfo.setIconFileElement(icon, existing.getIconFileName());
- osus.put(entry.getKey(), osuInfo);
- } else {
- osus.put(entry.getKey(), new OSUInfo(entry.getValue(),
- entry.getKey(), mOSUSequence.getAndIncrement()));
- }
- } else {
- // Maintain existing entries.
- osus.put(entry.getKey(), existing);
- }
- }
-
- mOSUMap.clear();
- mOSUMap.putAll(osus);
-
- mOSUSSIDs.clear();
- for (OSUInfo osuInfo : mOSUMap.values()) {
- mOSUSSIDs.add(osuInfo.getOsuSsid());
- }
-
- int mods = mIconCache.resolveIcons(mOSUMap.values());
-
- if (mOSUMap.isEmpty() || mods > 0) {
- notifyOSUCount();
- }
- }
-
- public void notifyIconReceived(long bssid, String fileName, byte[] data) {
- if (mIconCache.notifyIconReceived(bssid, fileName, data) > 0) {
- notifyOSUCount();
- }
- }
-
- public void doIconQuery(long bssid, String fileName) {
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- wifiManager.queryPasspointIcon(bssid, fileName);
- }
-
- private void notifyOSUCount() {
- int count = 0;
- for (OSUInfo existing : mOSUMap.values()) {
- if (existing.getIconStatus() == OSUInfo.IconStatus.Available) {
- count++;
- }
- }
- Log.d(TAG, "Latest OSU info: " + count + " with icons, map " + mOSUMap);
- mAppBridge.showOsuCount(count);
- }
-
- public void deauth(long bssid, boolean ess, int delay, String url)
- throws MalformedURLException {
- Log.d(TAG, String.format("De-auth imminent on %s, delay %ss to '%s'",
- ess ? "ess" : "bss", delay, url));
- // TODO: Missing framework functionality:
- // mWifiNetworkAdapter.setHoldoffTime(delay * Constants.MILLIS_IN_A_SEC, ess);
- String spName = mRemediationHandler.getCurrentSpName();
- mAppBridge.showDeauth(spName, ess, delay, url);
- }
-
- public void wnmRemediate(final long bssid, final String url, PasspointMatch match) {
- mRemediationHandler.wnmReceived(bssid, url);
- }
-
- public void remediationDone(String fqdn, boolean policy) {
- mRemediationHandler.remediationDone(fqdn, policy);
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/OSUMessageType.java b/packages/Osu/src/com/android/hotspot2/osu/OSUMessageType.java
deleted file mode 100644
index 8c1b50ac3380..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/OSUMessageType.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.android.hotspot2.osu;
-
-public enum OSUMessageType {
- PostDevData, ExchangeComplete, GetCertificate, Error
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/OSUOperationStatus.java b/packages/Osu/src/com/android/hotspot2/osu/OSUOperationStatus.java
deleted file mode 100644
index ddda89cc096b..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/OSUOperationStatus.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.android.hotspot2.osu;
-
-public enum OSUOperationStatus {
- UserInputComplete,
- UserInputAborted,
- ProvisioningSuccess,
- ProvisioningFailure
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/OSUResponse.java b/packages/Osu/src/com/android/hotspot2/osu/OSUResponse.java
deleted file mode 100644
index 1e4398df6508..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/OSUResponse.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package com.android.hotspot2.osu;
-
-import com.android.hotspot2.omadm.OMAConstants;
-import com.android.hotspot2.omadm.OMAException;
-import com.android.hotspot2.omadm.XMLNode;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public abstract class OSUResponse {
- private static final String SPPVersionAttribute = "sppVersion";
- private static final String SPPStatusAttribute = "sppStatus";
- private static final String SPPSessionIDAttribute = "sessionID";
-
- private final OSUMessageType mMessageType;
- private final String mVersion;
- private final String mSessionID;
- private final OSUStatus mStatus;
- private final OSUError mError;
- private final Map<String, String> mAttributes;
-
- protected OSUResponse(XMLNode root, OSUMessageType messageType, String... attributes)
- throws OMAException {
- mMessageType = messageType;
- String ns = root.getNameSpace() + ":";
- mVersion = root.getAttributeValue(ns + SPPVersionAttribute);
- mSessionID = root.getAttributeValue(ns + SPPSessionIDAttribute);
-
- String status = root.getAttributeValue(ns + SPPStatusAttribute);
- if (status == null) {
- throw new OMAException("Missing status");
- }
- mStatus = OMAConstants.mapStatus(status);
-
- if (mVersion == null || mSessionID == null || mStatus == null) {
- throw new OMAException("Incomplete request: " + root.getAttributes());
- }
-
- if (attributes != null) {
- mAttributes = new HashMap<>();
- for (String attribute : attributes) {
- String value = root.getAttributeValue(ns + attribute);
- if (value == null) {
- throw new OMAException("Missing attribute: " + attribute);
- }
- mAttributes.put(attribute, value);
- }
- } else {
- mAttributes = null;
- }
-
- if (mStatus == OSUStatus.Error) {
- OSUError error = null;
- String errorTag = ns + "sppError";
- for (XMLNode child : root.getChildren()) {
- if (child.getTag().equals(errorTag)) {
- error = OMAConstants.mapError(child.getAttributeValue("errorCode"));
- break;
- }
- }
- mError = error;
- } else {
- mError = null;
- }
- }
-
- public OSUMessageType getMessageType() {
- return mMessageType;
- }
-
- public String getVersion() {
- return mVersion;
- }
-
- public String getSessionID() {
- return mSessionID;
- }
-
- public OSUStatus getStatus() {
- return mStatus;
- }
-
- public OSUError getError() {
- return mError;
- }
-
- protected Map<String, String> getAttributes() {
- return mAttributes;
- }
-
- @Override
- public String toString() {
- return String.format("%s version '%s', status %s, session-id '%s'%s",
- mMessageType, mVersion, mStatus, mSessionID, mError != null
- ? (" (" + mError + ")") : "");
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/OSUSocketFactory.java b/packages/Osu/src/com/android/hotspot2/osu/OSUSocketFactory.java
deleted file mode 100644
index 1f5547bf1f9a..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/OSUSocketFactory.java
+++ /dev/null
@@ -1,451 +0,0 @@
-package com.android.hotspot2.osu;
-
-import android.net.Network;
-import android.util.Base64;
-import android.util.Log;
-
-import com.android.hotspot2.Utils;
-import com.android.hotspot2.flow.PlatformAdapter;
-import com.android.hotspot2.pps.HomeSP;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.net.URL;
-import java.security.GeneralSecurityException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.PrivateKey;
-import java.security.cert.CertPath;
-import java.security.cert.CertPathValidator;
-import java.security.cert.CertPathValidatorException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.PKIXCertPathChecker;
-import java.security.cert.PKIXParameters;
-import java.security.cert.TrustAnchor;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.net.SocketFactory;
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
-
-public class OSUSocketFactory {
- private static final long ConnectionTimeout = 10000L;
- private static final long ReconnectWait = 2000L;
-
- private static final String SecureHTTP = "https";
- private static final String UnsecureHTTP = "http";
- private static final String EKU_ID = "2.5.29.37";
- private static final Set<String> EKU_ID_SET = new HashSet<>(Arrays.asList(EKU_ID));
- private static final EKUChecker sEKUChecker = new EKUChecker();
-
- private final Network mNetwork;
- private final SocketFactory mSocketFactory;
- private final KeyManager mKeyManager;
- private final WFATrustManager mTrustManager;
- private final List<InetSocketAddress> mRemotes;
-
- public static Set<X509Certificate> buildCertSet() {
- try {
- CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
- Set<X509Certificate> set = new HashSet<>();
- for (String b64 : WFACerts) {
- ByteArrayInputStream bis = new ByteArrayInputStream(
- Base64.decode(b64, Base64.DEFAULT));
- X509Certificate cert = (X509Certificate) certFactory.generateCertificate(bis);
- set.add(cert);
- }
- return set;
- } catch (CertificateException ce) {
- Log.e(OSUManager.TAG, "Cannot build CA cert set");
- return null;
- }
- }
-
- public static OSUSocketFactory getSocketFactory(KeyStore ks, HomeSP homeSP,
- OSUFlowManager.FlowType flowType,
- Network network, URL url, KeyManager km,
- boolean enforceSecurity)
- throws GeneralSecurityException, IOException {
-
- if (enforceSecurity && !url.getProtocol().equalsIgnoreCase(SecureHTTP)) {
- throw new IOException("Protocol '" + url.getProtocol() + "' is not secure");
- }
- return new OSUSocketFactory(ks, homeSP, flowType, network, url, km);
- }
-
- private OSUSocketFactory(KeyStore ks, HomeSP homeSP, OSUFlowManager.FlowType flowType,
- Network network,
- URL url, KeyManager km) throws GeneralSecurityException, IOException {
- mNetwork = network;
- mKeyManager = km;
- mTrustManager = new WFATrustManager(ks, homeSP, flowType);
- int port;
- switch (url.getProtocol()) {
- case UnsecureHTTP:
- mSocketFactory = new DefaultSocketFactory();
- port = url.getPort() > 0 ? url.getPort() : 80;
- break;
- case SecureHTTP:
- SSLContext tlsContext = SSLContext.getInstance("TLSv1");
- tlsContext.init(km != null ? new KeyManager[]{km} : null,
- new TrustManager[]{mTrustManager}, null);
- mSocketFactory = tlsContext.getSocketFactory();
- port = url.getPort() > 0 ? url.getPort() : 443;
- break;
- default:
- throw new IOException("Bad URL: " + url);
- }
- if (OSUManager.R2_MOCK && url.getHost().endsWith(".wi-fi.org")) {
- // !!! Warning: Ruckus hack!
- mRemotes = new ArrayList<>(1);
- mRemotes.add(new InetSocketAddress(InetAddress.getByName("10.123.107.107"), port));
- } else {
- InetAddress[] remotes = mNetwork.getAllByName(url.getHost());
- android.util.Log.d(OSUManager.TAG, "'" + url.getHost() + "' resolves to " +
- Arrays.toString(remotes));
- if (remotes == null || remotes.length == 0) {
- throw new IOException("Failed to look up host from " + url);
- }
- mRemotes = new ArrayList<>(remotes.length);
- for (InetAddress remote : remotes) {
- mRemotes.add(new InetSocketAddress(remote, port));
- }
- }
- Collections.shuffle(mRemotes);
- }
-
- public void reloadKeys(Map<OSUCertType, List<X509Certificate>> certs, PrivateKey key)
- throws IOException {
- if (mKeyManager instanceof ClientKeyManager) {
- ((ClientKeyManager) mKeyManager).reloadKeys(certs, key);
- }
- }
-
- public Socket createSocket() throws IOException {
- Socket socket = mSocketFactory.createSocket();
- mNetwork.bindSocket(socket);
-
- long bail = System.currentTimeMillis() + ConnectionTimeout;
- boolean success = false;
-
- while (System.currentTimeMillis() < bail) {
- for (InetSocketAddress remote : mRemotes) {
- try {
- socket.connect(remote);
- Log.d(OSUManager.TAG, "Connection " + socket.getLocalSocketAddress() +
- " to " + socket.getRemoteSocketAddress());
- success = true;
- break;
- } catch (IOException ioe) {
- Log.d(OSUManager.TAG, "Failed to connect to " + remote + ": " + ioe);
- socket = mSocketFactory.createSocket();
- mNetwork.bindSocket(socket);
- }
- }
- if (success) {
- break;
- }
- Utils.delay(ReconnectWait);
- }
- if (!success) {
- throw new IOException("No available network");
- }
- return socket;
- }
-
- public X509Certificate getOSUCertificate(URL url) throws GeneralSecurityException {
- String fqdn = url.getHost();
- for (X509Certificate certificate : mTrustManager.getTrustChain()) {
- for (List<?> name : certificate.getSubjectAlternativeNames()) {
- if (name.size() >= SPVerifier.DNSName &&
- name.get(0).getClass() == Integer.class &&
- name.get(1).toString().equals(fqdn)) {
- return certificate;
- }
- }
- }
- return null;
- }
-
- final class DefaultSocketFactory extends SocketFactory {
-
- DefaultSocketFactory() {
- }
-
- @Override
- public Socket createSocket() throws IOException {
- return new Socket();
- }
-
- @Override
- public Socket createSocket(String host, int port) throws IOException {
- return new Socket(host, port);
- }
-
- @Override
- public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
- throws IOException {
- return new Socket(host, port, localHost, localPort);
- }
-
- @Override
- public Socket createSocket(InetAddress host, int port) throws IOException {
- return new Socket(host, port);
- }
-
- @Override
- public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
- int localPort) throws IOException {
- return new Socket(address, port, localAddress, localPort);
- }
- }
-
- private static class WFATrustManager implements X509TrustManager {
- private final KeyStore mKeyStore;
- private final HomeSP mHomeSP;
- private final OSUFlowManager.FlowType mFlowType;
- private X509Certificate[] mTrustChain;
-
- private WFATrustManager(KeyStore ks, HomeSP homeSP, OSUFlowManager.FlowType flowType)
- throws CertificateException {
- mKeyStore = ks;
- mHomeSP = homeSP;
- mFlowType = flowType;
- }
-
- @Override
- public void checkClientTrusted(X509Certificate[] chain, String authType)
- throws CertificateException {
- // N/A
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] chain, String authType)
- throws CertificateException {
- Log.d("TLSOSU", "Checking " + chain.length + " certs.");
-
- try {
- CertPathValidator validator =
- CertPathValidator.getInstance(CertPathValidator.getDefaultType());
- CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
- CertPath path = certFactory.generateCertPath(
- Arrays.asList(chain));
- Set<TrustAnchor> trustAnchors = new HashSet<>();
- if (mHomeSP == null) {
- for (X509Certificate cert : getRootCerts(mKeyStore)) {
- trustAnchors.add(new TrustAnchor(cert, null));
- }
- } else {
- String prefix = mFlowType == OSUFlowManager.FlowType.Remediation ?
- PlatformAdapter.CERT_REM_ALIAS : PlatformAdapter.CERT_POLICY_ALIAS;
-
- X509Certificate cert = getCert(mKeyStore, prefix + mHomeSP.getFQDN());
- if (cert == null) {
- cert = getCert(mKeyStore,
- PlatformAdapter.CERT_SHARED_ALIAS + mHomeSP.getFQDN());
- }
- if (cert == null) {
- for (X509Certificate root : getRootCerts(mKeyStore)) {
- trustAnchors.add(new TrustAnchor(root, null));
- }
- } else {
- trustAnchors.add(new TrustAnchor(cert, null));
- }
- }
- PKIXParameters params = new PKIXParameters(trustAnchors);
- params.setRevocationEnabled(false);
- params.addCertPathChecker(sEKUChecker);
- validator.validate(path, params);
- mTrustChain = chain;
- } catch (GeneralSecurityException gse) {
- throw new SecurityException(gse);
- }
- mTrustChain = chain;
- }
-
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- return null;
- }
-
- public X509Certificate[] getTrustChain() {
- return mTrustChain != null ? mTrustChain : new X509Certificate[0];
- }
- }
-
- private static X509Certificate getCert(KeyStore keyStore, String alias)
- throws KeyStoreException {
- Certificate cert = keyStore.getCertificate(alias);
- if (cert != null && cert instanceof X509Certificate) {
- return (X509Certificate) cert;
- }
- return null;
- }
-
- public static Set<X509Certificate> getRootCerts(KeyStore keyStore) throws KeyStoreException {
- Set<X509Certificate> certSet = new HashSet<>();
- int index = 0;
- for (int n = 0; n < 1000; n++) {
- Certificate cert = keyStore.getCertificate(
- String.format("%s%d", PlatformAdapter.CERT_WFA_ALIAS, index));
- if (cert == null) {
- break;
- } else if (cert instanceof X509Certificate) {
- certSet.add((X509Certificate) cert);
- }
- index++;
- }
- return certSet;
- }
-
- private static class EKUChecker extends PKIXCertPathChecker {
- @Override
- public void init(boolean forward) throws CertPathValidatorException {
-
- }
-
- @Override
- public boolean isForwardCheckingSupported() {
- return true;
- }
-
- @Override
- public Set<String> getSupportedExtensions() {
- return EKU_ID_SET;
- }
-
- @Override
- public void check(Certificate cert, Collection<String> unresolvedCritExts)
- throws CertPathValidatorException {
- Log.d(OSUManager.TAG, "Checking EKU " + unresolvedCritExts);
- unresolvedCritExts.remove(EKU_ID);
- }
- }
-
- /*
- *
- Subject: CN=osu-server.r2-testbed-rks.wi-fi.org, O=Intel Corporation CCG DRD, C=US
- Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11
- Validity: [From: Wed Jan 28 16:00:00 PST 2015,
- To: Sat Jan 28 15:59:59 PST 2017]
- Issuer: CN="NetworkFX, Inc. Hotspot 2.0 Intermediate CA", OU=OSU CA - 01, O="NetworkFX, Inc.", C=US
- SerialNumber: [ 312af3db 138eae19 1defbce2 e2b88b55]
- *
- *
- Subject: CN="NetworkFX, Inc. Hotspot 2.0 Intermediate CA", OU=OSU CA - 01, O="NetworkFX, Inc.", C=US
- Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11
- Validity: [From: Tue Nov 19 16:00:00 PST 2013,
- To: Sun Nov 19 15:59:59 PST 2023]
- Issuer: CN=Hotspot 2.0 Trust Root CA - 01, O=WFA Hotspot 2.0, C=US
- SerialNumber: [ 4152b1b0 301495f3 8fa76428 2ef41046]
- */
-
- public static final String[] WFACerts = {
- "MIIFbDCCA1SgAwIBAgIQDLMPcPKGpDPguQmJ3gHttzANBgkqhkiG9w0BAQsFADBQ" +
- "MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPV0ZBIEhvdHNwb3QgMi4wMScwJQYDVQQD" +
- "Ex5Ib3RzcG90IDIuMCBUcnVzdCBSb290IENBIC0gMDMwHhcNMTMxMjA4MTIwMDAw" +
- "WhcNNDMxMjA4MTIwMDAwWjBQMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPV0ZBIEhv" +
- "dHNwb3QgMi4wMScwJQYDVQQDEx5Ib3RzcG90IDIuMCBUcnVzdCBSb290IENBIC0g" +
- "MDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCsdEtReIUbMlO+hR6b" +
- "yQk4nGVITv3meYTaDeVwZnQVal8EjHuu4Kd89g8yRYVTv3J1kq9ukE7CDrDehrXK" +
- "ym+8VlR7ro0lB/lwRyNk3W7yNccg3AknQ0x5fKVwcFznwD/FYg37owGmhGFtpMTB" +
- "cxzreQaLXvLta8YNlJU10ZkfputBpzi9bLPWsLOkIrQw7KH1Wc+Oiy4hUMUbTlSi" +
- "cjqacKPR188mVIoxxUoICHyVV1KvMmYZrVdc/b5dbmd0haMHxC0VSqbydXxxS7vv" +
- "/lCrC2d5qbKE66PiuBPkhzyU7SI9C8GU/S7akYm1MMSTn5W7lSp2AWRDnf9LQg51" +
- "dLvDxJ7t2fruXtSkkqG/cwY1yQI8O+WZYPDThKPcDmNbaxVE9lOizAHXFVsfYrXA" +
- "PbbMOkzKehYwaIikmNgcpxtQNw+wikJiZb9N8VwwtwHK71XEFi+n5DGlPa9VDYgB" +
- "YkBcxvVo2rbE3i3teQgHm+pWZNP08aFNWwMk9yQkm/SOGdLq1jLbQA9yd7fyR1Ct" +
- "W1GLzKi1Ojr/6XiB9/noL3oxP/+gb8OSgcqVfkZp4QLvrGdlKiOI2fE7Bslmzn6l" +
- "B3UTpApjab7BQ99rCXzDwt3Xd7IrCtAJNkxi302J7k6hnGlW8S4oPQBElkOtoH9y" +
- "XEhp9rNS0lZiuwtFmWW2q50fkQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G" +
- "A1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUZw5JLGEXnuvt4FTnhNmbrWRgc2UwDQYJ" +
- "KoZIhvcNAQELBQADggIBAFPoGFDyzFg9B9+jJUPGW32omftBhChVcgjllI07RCie" +
- "KTMBi47+auuLgiMox3xRyP7/dX7YaUeMXEQ1BMv6nlrsXWv1lH4yu+RNuehPlqRs" +
- "fY351mAfPtQ654SBUi0Wg++9iyTOfgF5a9IWEDt4lnSZMvA4vlw8pUCz6zpKXHnA" +
- "RXKrpY3bU+2dnrFDKR0XQhmAQdo7UvdsT1elVoFIxHhLpwfzx+kpEhtrXw3nGgt+" +
- "M4jNp684XoWpxVGaQ4Vvv00Sm2DQ8jq2sf9F+kRWszZpQOTiMGKZr0lX2CI5cww1" +
- "dfmd1BkAjI9cIWLkD8YSeaggZzvYe1o9d7e7lKfdJmjDlSQ0uBiG77keUK4tF2fi" +
- "xFTxibtPux56p3GYQ2GdRsBaKjH3A3HMJSKXwIGR+wb1sgz/bBdlyJSylG8hYD//" +
- "0Hyo+UrMUszAdszoPhMY+4Ol3QE3QRWzXi+W/NtKeYD2K8xUzjZM10wMdxCfoFOa" +
- "8bzzWnxZQlnu880ULUSHIxDPeE+DDZYYOaN1hV2Rh/hrFKvvV+gJj2eXHF5G7y9u" +
- "Yg7nHYCCf7Hy8UTIXDtAAeDCQNon1ReN8G+XOqhLQ9TalmnJ5U5ARtC0MdQDht7T" +
- "DZpWeEVv+pQHARX9GDV/T85MV2RPJWKqfZ6kK0gvQDkunADdg8IhZAjwMMx3k6B/",
-
- "MIIFbDCCA1SgAwIBAgIQaAV8NQv/Xdusi4IU+tpUfjANBgkqhkiG9w0BAQsFADBQ" +
- "MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPV0ZBIEhvdHNwb3QgMi4wMScwJQYDVQQD" +
- "Ex5Ib3RzcG90IDIuMCBUcnVzdCBSb290IENBIC0gMDEwHhcNMTMxMTIwMDAwMDAw" +
- "WhcNNDMxMTE5MjM1OTU5WjBQMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPV0ZBIEhv" +
- "dHNwb3QgMi4wMScwJQYDVQQDEx5Ib3RzcG90IDIuMCBUcnVzdCBSb290IENBIC0g" +
- "MDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/gf4CHxWjr2EcktAZ" +
- "pHT4z1yFYZILD3ZVqvzzXBK+YKjWhjsgZ28Z1VwXqu51JvVzwTGDalPf5m7zMcJW" +
- "CpPtPBdxxwQ/cBDPK4w+/sCuYYSddlMLzwZ/IgwFike12tKTR7Kk7Nk6ghrYaxCG" +
- "R+QEZDVrxITj79vGpgk2otVnMI4d3H9mWt1o6Lx+hVioyBgOvmo2OWHR2uKkbg5h" +
- "tktXqmBEtzK+qDqIIUY4WRRZHxlOaF2/EdIIGhXlf+Vlr13aPqOPiDiE08o+GARz" +
- "TIp8BrW2boo0+2kpEFUKiqc427vOYEkUdSMfwu4aGOcuOewc8sk6ztquL/JcPROL" +
- "VSFSSFR3HKhUto8EJcHEEG9wzcOi1OO/OOSVxjNwiaV/hB9Ed1wvoBhiJ+C+Q8/K" +
- "HXmoH/ankXDaB06yjt2Ojemt0nO45qlarRj8tO7zbpghJuJxztur47U7PJta7Zcg" +
- "z7kOPJPTAbzmOU2TXt1pXO1hVnSlV+M1rRwe7qivnSMMrTnkX15YWmyK27/tgJeu" +
- "muR2YzvPwPtF/m1N0bRKI7FW05NYg3smItFq0E/eyf/orgolcXTZ7zNRyRGnjWNs" +
- "/w9SDbdby0uVUfdN4V/5uC4HBmA1rikoBbGZ+nzCtesY4yW8eEwMfguVpNT3ueaU" +
- "q30nufeY2VnA3Rv1WH8TaeZU+wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G" +
- "A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU+RjGVZbebjpzEPfthaTLqbvXMiEwDQYJ" +
- "KoZIhvcNAQELBQADggIBABj3LP1UXVa16HYeXC1+GU1dX/cla1n1bwpIlxRnCZ5/" +
- "3I3zGw/nRnsLUTkGf8q3XCgin+jX22kyzzQNrgepn0zqBsmAj+pjUUwWzYQUzphc" +
- "Uzmg4PJRWaEaGG3kvD+wJEC0pWvIhe48qcq8FZCCmjbvecEVn5mM0smPzPyUjf/o" +
- "fjUMQvVWqug/Ff5HT6kbyDWhC3nD+8IZ5PjyO85OnoBnQkr8WYwr24XJgO2HS2rs" +
- "W40CzQe3Kdg7HHyef+/iyLYTBJH7EUJPCHGVQtZ3q0aNqURkutXJ/CxKJYMcNTEB" +
- "x+a09EhZ6DOHQDqsdTuAqGh3VyrxhFk+3suNsxoh6XaRK10VslvdNB/1YKfU8DWe" +
- "V6XfDH/TR0NIL04exUp3rER8sERulpJGBOnaG6OQKh4bFYDB406+QfusQnvO0aYR" +
- "UXJzf01B15HRJgpZsggpIuex0UDcJhTTpkRfTj8L4ayUce2ZRsGn3dBaT9ZMx4o9" +
- "E/YsQyOpfw28gM5u+zZt4BJz4gAaRGbp4r4sk5Vm/P1/0EXJ70Du6K9d0HAHtpEv" +
- "Y94Ww5W6fpMDdyAKYTXZBgTX3cqtikNkLX/kHH8l4o/XW2sXqU3X7vOYqgeVYoD9" +
- "NnhZXYCerH4Se5Lgj8/KhXxRWtcn3XduMdkC6UTApMooA64Vs508173Z3lJn2SeQ",
-
- "MIIFXTCCA0WgAwIBAgIBATANBgkqhkiG9w0BAQsFADBQMQswCQYDVQQGEwJVUzEY" +
- "MBYGA1UECgwPV0ZBIEhvdHNwb3QgMi4wMScwJQYDVQQDDB5Ib3RzcG90IDIuMCBU" +
- "cnVzdCBSb290IENBIC0gMDIwHhcNMTMxMjAyMjA1NzU3WhcNNDMxMjAyMjA1NTAz" +
- "WjBQMQswCQYDVQQGEwJVUzEYMBYGA1UECgwPV0ZBIEhvdHNwb3QgMi4wMScwJQYD" +
- "VQQDDB5Ib3RzcG90IDIuMCBUcnVzdCBSb290IENBIC0gMDIwggIiMA0GCSqGSIb3" +
- "DQEBAQUAA4ICDwAwggIKAoICAQDCSoMqNhtTwbnIsINp6nUhx5UFuq9ZQoTv+KDk" +
- "vAajT0di6+cQG3sAVvZLySmJoiBAv3PizYYLOD4eGMrFQRqi7PmSJ83WqNv23ZYF" +
- "ryFFJiy/URXc/ALDuB3dgElPt24Mx7n2xDPAh9t82HTmuskpQRrsyg9QPoi5rRRS" +
- "Djm5mjFJjKChq99RWcweNV/KGH1sTwcmlDmNMScK16A+BBNiSvmZlsGJgAlP369k" +
- "lnNqt6UiDhepcktuKpHmSvNel+c/xqzR0gURfUnXcZhzjzS94Rx5O+CNWL4EGiJq" +
- "qKAfk99j/lbD0MWYo7Rh0UKQlXSdohWDiV93hxvvfugej8KUOIb+1wmd1Fi+lwDZ" +
- "bR2yg2f0qyxbC/tAV4JJNnuDLFb19leD78x+68eAnlbMi+xMH5lINs15+26s2H5d" +
- "lx9kwRDBJq02LuHnen6FLafWjejnnBQ/PuGD0ACvBegSsDKDaCuTAnTNS6MDmQr4" +
- "wza08iX360ZN+BbSAnCK1YGa/7J7fhyydwxLJ7s5Eo0b6SUMY87FMc5XmkAk4xxL" +
- "MLqS2HMtqsGBI5JQT0SgH0ghE6DjMWArBTZcD+swuzTi1/Cz5+Z9Es8xJ3MPvSZW" +
- "pJi6VVB2eVMAqfHOj4ozHoVpvJypIVGRwWBzVRWom76R47utuRK6uKzoLiB1jwE5" +
- "vwHpUQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBxjAd" +
- "BgNVHQ4EFgQU5C9c1OMsB+/MOwl9OKG2D/XSwrUwDQYJKoZIhvcNAQELBQADggIB" +
- "AGULYE/VrnA3K0ptgHrWlQoPfp5wGvScgsmy0wp9qE3b6n/4bLehBKb5w4Y3JVA9" +
- "gjxoQ5xE2ssDtULZ3nKnGWmMN3qOBoRZCA6KjKs1860p09tm1ScUsajDJ15Tp1nI" +
- "zfR0oP63+2bJx+JXM8fPKOJe245hj2rs1c3JXsGCe+UVrlGsotG+wR0PdrejaXJ8" +
- "HbhBQHcbhgjsD1Gb6Egm4YxRKAtcVY3q9EKKWAGhbC1qvCh1iLNKo3FeGgm2r3EG" +
- "L4cYJBb2fhSKltjISqCDhYq4tplOIeQSJJyJC8gfW/BnMU39lTjNgnSjjGPLQXGV" +
- "+Ulb/CgNMJ3RhRJdBoLcpIm/EeLx6JLq/2Erxy7CxjaSOcD0UKa14+dzLSHVsXft" +
- "HZuOy548X8m18KruSZsf5uAT3c7NqlXtr9YgOVUqSJykNAHTGi/BHB1dC2clKvxN" +
- "ElfLWWrG9yaAd5TFW0+3wsaDIwRZL584AsFwwAD3KMo1oU/2zRvtm0E+VghsuD/Z" +
- "IE1xaVGTPaL7ph/YgC9+0rGHieauT8SXz6Ryp3h0RtYMLFZOMTKM7xjmcbMZDwrO" +
- "c+J/XjK9dbiCqlx5/B8P0xWaYYHzvE5/fafiPYzoGyFVUXquu0dFCCQrvjF/y0tC" +
- "TPm4hQim3k1F+5NChcbeNggN+kq+VdlSqPhQEuOY+kNv"
- };
-
- //private static final Set<TrustAnchor> sTrustAnchors = buildCertSet();
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/OSUStatus.java b/packages/Osu/src/com/android/hotspot2/osu/OSUStatus.java
deleted file mode 100644
index 00f0634ed121..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/OSUStatus.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.android.hotspot2.osu;
-
-public enum OSUStatus {
- OK, ProvComplete, RemediationComplete, UpdateComplete, ExchangeComplete, Unknown, Error
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/OSUWebView.java b/packages/Osu/src/com/android/hotspot2/osu/OSUWebView.java
deleted file mode 100644
index a6778c82021a..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/OSUWebView.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package com.android.hotspot2.osu;
-
-import android.annotation.Nullable;
-import android.app.Activity;
-import android.graphics.Bitmap;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.http.SslError;
-import android.os.Bundle;
-import android.util.Log;
-import android.util.TypedValue;
-import android.webkit.SslErrorHandler;
-import android.webkit.WebSettings;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-
-import com.android.hotspot2.R;
-
-public class OSUWebView extends Activity {
- public static final String OSU_URL = "com.android.hotspot2.osu.URL";
- public static final String OSU_NETWORK = "com.android.hotspot2.osu.NETWORK";
-
- private String mUrl;
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Log.d(OSUManager.TAG, "Opening OSU Web View");
-
- ConnectivityManager connectivityManager = ConnectivityManager.from(this);
-
- mUrl = getIntent().getStringExtra(OSU_URL);
- Network network = getIntent().getParcelableExtra(OSU_NETWORK);
- connectivityManager.bindProcessToNetwork(network);
-
- getActionBar().setDisplayShowHomeEnabled(false);
- setContentView(R.layout.osu_web_view);
- getActionBar().setDisplayShowHomeEnabled(false);
-
- final WebView myWebView = findViewById(R.id.webview);
- myWebView.clearCache(true);
- WebSettings webSettings = myWebView.getSettings();
- webSettings.setJavaScriptEnabled(true);
- MyWebViewClient mWebViewClient = new MyWebViewClient();
- myWebView.setWebViewClient(mWebViewClient);
- Log.d(OSUManager.TAG, "OSU Web View to " + mUrl);
- myWebView.loadUrl(mUrl);
- Log.d(OSUManager.TAG, "OSU Web View loading");
- //myWebView.setWebChromeClient(new MyWebChromeClient());
- // Start initial page load so WebView finishes loading proxy settings.
- // Actual load of mUrl is initiated by MyWebViewClient.
- //myWebView.loadData("", "text/html", null);
- }
-
- private class MyWebViewClient extends WebViewClient {
- private static final String INTERNAL_ASSETS = "file:///android_asset/";
- // How many Android device-independent-pixels per scaled-pixel
- // dp/sp = (px/sp) / (px/dp) = (1/sp) / (1/dp)
- private final float mDpPerSp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 1,
- getResources().getDisplayMetrics()) /
- TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1,
- getResources().getDisplayMetrics());
- private int mPagesLoaded;
-
- // If we haven't finished cleaning up the history, don't allow going back.
- public boolean allowBack() {
- return mPagesLoaded > 1;
- }
-
- // Convert Android device-independent-pixels (dp) to HTML size.
- private String dp(int dp) {
- // HTML px's are scaled just like dp's, so just add "px" suffix.
- return Integer.toString(dp) + "px";
- }
-
- // Convert Android scaled-pixels (sp) to HTML size.
- private String sp(int sp) {
- // Convert sp to dp's.
- float dp = sp * mDpPerSp;
- // Apply a scale factor to make things look right.
- dp *= 1.3;
- // Convert dp's to HTML size.
- return dp((int)dp);
- }
-
- @Override
- public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
- Log.d(OSUManager.TAG, "TLS error in Web View: " + error);
- }
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/PostDevDataResponse.java b/packages/Osu/src/com/android/hotspot2/osu/PostDevDataResponse.java
deleted file mode 100644
index 12b9997f4761..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/PostDevDataResponse.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.android.hotspot2.osu;
-
-import com.android.hotspot2.omadm.OMAException;
-import com.android.hotspot2.omadm.XMLNode;
-import com.android.hotspot2.osu.commands.OSUCommandData;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-public class PostDevDataResponse extends OSUResponse {
- private final List<OSUCommand> mOSUCommands;
-
- public PostDevDataResponse(XMLNode root) throws OMAException {
- super(root, OSUMessageType.PostDevData);
-
- if (getStatus() == OSUStatus.Error) {
- mOSUCommands = null;
- return;
- }
-
- mOSUCommands = new ArrayList<>();
- for (XMLNode child : root.getChildren()) {
- mOSUCommands.add(new OSUCommand(child));
- }
- }
-
- public OSUCommandID getOSUCommand() {
- return mOSUCommands.size() == 1 ? mOSUCommands.get(0).getOSUCommand() : null;
- }
-
- public ExecCommand getExecCommand() {
- return mOSUCommands.size() == 1 ? mOSUCommands.get(0).getExecCommand() : null;
- }
-
- public OSUCommandData getCommandData() {
- return mOSUCommands.size() == 1 ? mOSUCommands.get(0).getCommandData() : null;
- }
-
- public Collection<OSUCommand> getCommands() {
- return Collections.unmodifiableCollection(mOSUCommands);
- }
-
- @Override
- public String toString() {
- return super.toString() + ", commands " + mOSUCommands;
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/RequestReason.java b/packages/Osu/src/com/android/hotspot2/osu/RequestReason.java
deleted file mode 100644
index db222b4bf47d..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/RequestReason.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.android.hotspot2.osu;
-
-public enum RequestReason {
- SubRegistration,
- SubProvisioning,
- SubRemediation,
- InputComplete,
- NoClientCert,
- CertEnrollmentComplete,
- CertEnrollmentFailed,
- SubMetaDataUpdate,
- PolicyUpdate,
- NextCommand,
- MOUpload,
- Unspecified
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/ResponseFactory.java b/packages/Osu/src/com/android/hotspot2/osu/ResponseFactory.java
deleted file mode 100644
index 3e236a7a6c58..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/ResponseFactory.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.android.hotspot2.osu;
-
-import com.android.hotspot2.omadm.OMAException;
-import com.android.hotspot2.omadm.XMLNode;
-
-public interface ResponseFactory {
- public OSUResponse buildResponse(XMLNode root) throws OMAException;
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/SOAPBuilder.java b/packages/Osu/src/com/android/hotspot2/osu/SOAPBuilder.java
deleted file mode 100644
index e2f91ea5eff9..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/SOAPBuilder.java
+++ /dev/null
@@ -1,188 +0,0 @@
-package com.android.hotspot2.osu;
-
-import com.android.hotspot2.omadm.MOTree;
-import com.android.hotspot2.omadm.OMAConstants;
-import com.android.hotspot2.omadm.XMLNode;
-
-import java.util.EnumMap;
-import java.util.HashMap;
-import java.util.Map;
-
-public class SOAPBuilder {
- private static final String EnvelopeTag = "s12:Envelope";
- private static final String BodyTag = "s12:Body";
-
- private static final Map<String, String> sEnvelopeAttributes = new HashMap<>(2);
- private static final Map<RequestReason, String> sRequestReasons =
- new EnumMap<>(RequestReason.class);
-
- static {
- sEnvelopeAttributes.put("xmlns:s12", "http://www.w3.org/2003/05/soap-envelope");
- sEnvelopeAttributes.put("xmlns:spp",
- "http://www.wi-fi.org/specifications/hotspot2dot0/v1.0/spp");
-
- sRequestReasons.put(RequestReason.SubRegistration, "Subscription registration");
- sRequestReasons.put(RequestReason.SubProvisioning, "Subscription provisioning");
- sRequestReasons.put(RequestReason.SubRemediation, "Subscription remediation");
- sRequestReasons.put(RequestReason.InputComplete, "User input completed");
- sRequestReasons.put(RequestReason.NoClientCert, "No acceptable client certificate");
- sRequestReasons.put(RequestReason.CertEnrollmentComplete,
- "Certificate enrollment completed");
- sRequestReasons.put(RequestReason.CertEnrollmentFailed, "Certificate enrollment failed");
- sRequestReasons.put(RequestReason.SubMetaDataUpdate, "Subscription metadata update");
- sRequestReasons.put(RequestReason.PolicyUpdate, "Policy update");
- sRequestReasons.put(RequestReason.NextCommand, "Retrieve next command");
- sRequestReasons.put(RequestReason.MOUpload, "MO upload");
- sRequestReasons.put(RequestReason.Unspecified, "Unspecified");
- }
-
- public static String buildPostDevDataResponse(RequestReason reason, String sessionID,
- String redirURI, MOTree... mos) {
- XMLNode envelope = buildEnvelope();
- buildSppPostDevData(envelope.getChildren().get(0), sessionID, reason, redirURI, mos);
- return envelope.toString();
- }
-
- public static String buildUpdateResponse(String sessionID, OSUError error) {
- XMLNode envelope = buildEnvelope();
- buildSppUpdateResponse(envelope.getChildren().get(0), sessionID, error);
- return envelope.toString();
- }
-
- private static XMLNode buildEnvelope() {
- XMLNode envelope = new XMLNode(null, EnvelopeTag, sEnvelopeAttributes);
- envelope.addChild(new XMLNode(envelope, BodyTag, (Map<String, String>) null));
- return envelope;
- }
-
- private static XMLNode buildSppPostDevData(XMLNode parent, String sessionID,
- RequestReason reason, String redirURI,
- MOTree... mos) {
- Map<String, String> pddAttributes = new HashMap<>();
- pddAttributes.put(OMAConstants.TAG_Version, OMAConstants.MOVersion);
- pddAttributes.put("requestReason", sRequestReasons.get(reason));
- if (sessionID != null) {
- pddAttributes.put(OMAConstants.TAG_SessionID, sessionID);
- }
- if (redirURI != null) {
- pddAttributes.put("redirectURI", redirURI);
- }
-
- XMLNode pddNode = new XMLNode(parent, OMAConstants.TAG_PostDevData, pddAttributes);
-
- XMLNode vNode = new XMLNode(pddNode, OMAConstants.TAG_SupportedVersions,
- (HashMap<String, String>) null);
- vNode.setText("1.0");
- pddNode.addChild(vNode);
-
- XMLNode moNode = new XMLNode(pddNode, OMAConstants.TAG_SupportedMOs,
- (HashMap<String, String>) null);
- StringBuilder sb = new StringBuilder();
- boolean first = true;
- for (String urn : OMAConstants.SupportedMO_URNs) {
- if (first) {
- first = false;
- } else {
- sb.append(' ');
- }
- sb.append(urn);
- }
- moNode.setText(sb.toString());
- pddNode.addChild(moNode);
-
- if (mos != null) {
- for (MOTree moTree : mos) {
- Map<String, String> map = null;
- if (moTree.getUrn() != null) {
- map = new HashMap<>(1);
- map.put(OMAConstants.SppMOAttribute, moTree.getUrn());
- }
- moNode = new XMLNode(pddNode, OMAConstants.TAG_MOContainer, map);
- moNode.setText(moTree.toXml());
- pddNode.addChild(moNode);
- }
- }
-
- parent.addChild(pddNode);
- return pddNode;
- }
-
- private static XMLNode buildSppUpdateResponse(XMLNode parent, String sessionID,
- OSUError error) {
- Map<String, String> urAttributes = new HashMap<>();
- urAttributes.put(OMAConstants.TAG_Version, OMAConstants.MOVersion);
- if (sessionID != null) {
- urAttributes.put(OMAConstants.TAG_SessionID, sessionID);
- }
- if (error == null) {
- urAttributes.put(OMAConstants.TAG_Status, OMAConstants.mapStatus(OSUStatus.OK));
- } else {
- urAttributes.put(OMAConstants.TAG_Status, OMAConstants.mapStatus(OSUStatus.Error));
- }
-
- XMLNode urNode = new XMLNode(parent, OMAConstants.TAG_UpdateResponse, urAttributes);
-
- if (error != null) {
- Map<String, String> errorAttributes = new HashMap<>();
- errorAttributes.put("errorCode", OMAConstants.mapError(error));
- XMLNode errorNode = new XMLNode(urNode, OMAConstants.TAG_Error, errorAttributes);
- urNode.addChild(errorNode);
- }
-
- parent.addChild(urNode);
- return urNode;
- }
-
- /*
- <xsd:element name="sppUpdateResponse">
- <xsd:annotation>
- <xsd:documentation>SOAP method used by SPP client to confirm installation of MO addition or update.</xsd:documentation>
- </xsd:annotation>
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element ref="sppError" minOccurs="0"/>
- <xsd:any namespace="##other" maxOccurs="unbounded" minOccurs="0"/>
- </xsd:sequence>
- <xsd:attribute ref="sppVersion" use="required"/>
- <xsd:attribute ref="sppStatus" use="required"/>
- <xsd:attribute ref="sessionID" use="required"/>
- <xsd:anyAttribute namespace="##other"/>
- </xsd:complexType>
- </xsd:element>
-
- <xsd:element name="sppError">
- <xsd:annotation>
- <xsd:documentation>Error response.</xsd:documentation>
- </xsd:annotation>
- <xsd:complexType>
- <xsd:attribute name="errorCode" use="required">
- <xsd:simpleType>
- <xsd:restriction base="xsd:string">
- <xsd:enumeration value="SPP version not supported"/>
- <xsd:enumeration value="One or more mandatory MOs not supported"/>
- <xsd:enumeration value="Credentials cannot be provisioned at this time"/>
- <xsd:enumeration value="Remediation cannot be completed at this time"/>
- <xsd:enumeration value="Provisioning cannot be completed at this time"/>
- <xsd:enumeration value="Continue to use existing certificate"/>
- <xsd:enumeration value="Cookie invalid"/>
- <xsd:enumeration value="No corresponding web-browser-connection Session ID"/>
- <xsd:enumeration value="Permission denied"/>
- <xsd:enumeration value="Command failed"/>
- <xsd:enumeration value="MO addition or update failed"/>
- <xsd:enumeration value="Device full"/>
- <xsd:enumeration value="Bad management tree URI"/>
- <xsd:enumeration value="Requested entity too large"/>
- <xsd:enumeration value="Command not allowed"/>
- <xsd:enumeration value="Command not executed due to user"/>
- <xsd:enumeration value="Not found"/>
- <xsd:enumeration value="Other"/>
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:attribute>
- <xsd:anyAttribute namespace="##other"/>
- </xsd:complexType>
- </xsd:element>
-
-
- */
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/SOAPParser.java b/packages/Osu/src/com/android/hotspot2/osu/SOAPParser.java
deleted file mode 100644
index b848ba93073b..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/SOAPParser.java
+++ /dev/null
@@ -1,327 +0,0 @@
-package com.android.hotspot2.osu;
-
-import com.android.hotspot2.omadm.OMAException;
-import com.android.hotspot2.omadm.XMLNode;
-
-import org.xml.sax.SAXException;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.xml.parsers.ParserConfigurationException;
-
-public class SOAPParser {
-
- private static final String EnvelopeTag = "envelope";
- private static final String BodyTag = "body";
-
- private static final Map<String, ResponseFactory> sResponseMap = new HashMap<>();
-
- static {
- sResponseMap.put("spppostdevdataresponse", new ResponseFactory() {
- @Override
- public OSUResponse buildResponse(XMLNode root) throws OMAException {
- return new PostDevDataResponse(root);
- }
- });
- sResponseMap.put("sppexchangecomplete", new ResponseFactory() {
- @Override
- public OSUResponse buildResponse(XMLNode root) throws OMAException {
- return new ExchangeCompleteResponse(root);
- }
- });
- sResponseMap.put("getcertificate", new ResponseFactory() {
- @Override
- public OSUResponse buildResponse(XMLNode root) {
- return null;
- }
- });
- sResponseMap.put("spperror", new ResponseFactory() {
- @Override
- public OSUResponse buildResponse(XMLNode root) {
- return null;
- }
- });
- }
-
- private final XMLNode mResponseNode;
-
- public SOAPParser(InputStream in)
- throws ParserConfigurationException, SAXException, IOException {
- XMLNode root;
-
- try {
- XMLParser parser = new XMLParser(in);
- root = parser.getRoot();
- } finally {
- in.close();
- }
-
- String[] nsn = root.getTag().split(":");
- if (nsn.length > 2) {
- throw new OMAException("Bad root tag syntax: '" + root.getTag() + "'");
- } else if (!EnvelopeTag.equalsIgnoreCase(nsn[nsn.length - 1])) {
- throw new OMAException("Expected envelope: '" + root.getTag() + "'");
- }
-
- String bodyTag = nsn.length > 1 ? (nsn[0] + ":" + BodyTag) : BodyTag;
- XMLNode body = null;
-
- for (XMLNode child : root.getChildren()) {
- if (bodyTag.equalsIgnoreCase(child.getTag())) {
- body = child;
- break;
- }
- }
-
- if (body == null || body.getChildren().isEmpty()) {
- throw new OMAException("Missing SOAP body");
- }
-
- mResponseNode = body.getSoleChild();
- }
-
- public OSUResponse getResponse() throws OMAException {
- ResponseFactory responseFactory = sResponseMap.get(mResponseNode.getStrippedTag());
- if (responseFactory == null) {
- throw new OMAException("Unknown response type: '"
- + mResponseNode.getStrippedTag() + "'");
- }
- return responseFactory.buildResponse(mResponseNode);
- }
-
- public XMLNode getResponseNode() {
- return mResponseNode;
- }
-
-
- /*
- <xsd:element name="sppPostDevDataResponse">
- <xsd:annotation>
- <xsd:documentation>SOAP method response from SPP server.</xsd:documentation>
- </xsd:annotation>
- <xsd:complexType>
- <xsd:choice>
- <xsd:element ref="sppError"/>
- <xsd:element name="exec">
- <xsd:annotation>
- <xsd:documentation>Receipt of this element by a mobile device causes the following command to be executed.</xsd:documentation>
- </xsd:annotation>
- <xsd:complexType>
- <xsd:choice>
- <xsd:element name="launchBrowserToURI" type="httpsURIType">
- <xsd:annotation>
- <xsd:documentation>When the mobile device receives this command, it launches its default browser to the URI contained in this element. The URI must use HTTPS as the protocol and must contain an FQDN.</xsd:documentation>
- </xsd:annotation>
- </xsd:element>
- <xsd:element ref="getCertificate"/>
- <xsd:element name="useClientCertTLS">
- <xsd:annotation>
- <xsd:documentation>Command to mobile to re-negotiate the TLS connection using a client certificate of the accepted type or Issuer to authenticate with the Subscription server.</xsd:documentation>
- </xsd:annotation>
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element name="providerIssuerName" minOccurs="0"
- maxOccurs="unbounded">
- <xsd:complexType>
- <xsd:attribute name="name" type="xsd:string">
- <xsd:annotation>
- <xsd:documentation>The issuer name of an acceptable provider-issued certificate. The text of this element is formatted in accordance with the Issuer Name field in RFC-3280. This element is present only when acceptProviderCerts is true.</xsd:documentation>
- </xsd:annotation>
- </xsd:attribute>
- <xsd:anyAttribute namespace="##other"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:any namespace="##other" minOccurs="0"
- maxOccurs="unbounded"/>
- </xsd:sequence>
- <xsd:attribute name="acceptMfgCerts" type="xsd:boolean"
- use="optional" default="false">
- <xsd:annotation>
- <xsd:documentation>When this boolean is true, IEEE 802.1ar manufacturing certificates are acceptable for mobile device authentication.</xsd:documentation>
- </xsd:annotation>
- </xsd:attribute>
- <xsd:attribute name="acceptProviderCerts" type="xsd:boolean"
- use="optional" default="true">
- <xsd:annotation>
- <xsd:documentation>When this boolean is true, X509v3 certificates issued by providers identified in the providerIssuerName child element(s) are acceptable for mobile device authentication.</xsd:documentation>
- </xsd:annotation>
- </xsd:attribute>
- <xsd:anyAttribute namespace="##other"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="uploadMO" maxOccurs="unbounded">
- <xsd:annotation>
- <xsd:documentation>Command to mobile to upload the MO named in the moURN attribute to the SPP server.</xsd:documentation>
- </xsd:annotation>
- <xsd:complexType>
- <xsd:attribute ref="moURN"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:any namespace="##other" maxOccurs="unbounded" minOccurs="0">
- <xsd:annotation>
- <xsd:documentation>Element to allow the addition of new commands in the future.</xsd:documentation>
- </xsd:annotation>
- </xsd:any>
- </xsd:choice>
- <xsd:anyAttribute namespace="##other"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="addMO">
- <xsd:annotation>
- <xsd:documentation>This command causes an management object in the mobile devices management tree at the specified location to be added. If there is already a management object at that location, the object is replaced.</xsd:documentation>
- </xsd:annotation>
- <xsd:complexType>
- <xsd:simpleContent>
- <xsd:extension base="xsd:string">
- <xsd:attribute ref="managementTreeURI"/>
- <xsd:attribute ref="moURN"/>
- </xsd:extension>
- </xsd:simpleContent>
- </xsd:complexType>
- </xsd:element>
- <xsd:element maxOccurs="unbounded" name="updateNode">
- <xsd:annotation>
- <xsd:documentation>This command causes the update of an interior node and its child nodes (if any) at the location specified in the management tree URI attribute. The content of this element is the MO node XML.</xsd:documentation>
- </xsd:annotation>
- <xsd:complexType>
- <xsd:simpleContent>
- <xsd:extension base="xsd:string">
- <xsd:attribute ref="managementTreeURI"/>
- </xsd:extension>
- </xsd:simpleContent>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="noMOUpdate">
- <xsd:annotation>
- <xsd:documentation>This response is used when there is no command to be executed nor update of any MO required.</xsd:documentation>
- </xsd:annotation>
- </xsd:element>
- <xsd:any namespace="##other" minOccurs="0" maxOccurs="unbounded">
- <xsd:annotation>
- <xsd:documentation>For vendor-specific extensions or future needs.</xsd:documentation>
- </xsd:annotation>
- </xsd:any>
- </xsd:choice>
- <xsd:attribute ref="sppVersion" use="required"/>
- <xsd:attribute ref="sppStatus" use="required"/>
- <xsd:attribute ref="moreCommands" use="optional"/>
- <xsd:attribute ref="sessionID" use="required"/>
- <xsd:anyAttribute namespace="##other"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="sppUpdateResponse">
- <xsd:annotation>
- <xsd:documentation>SOAP method used by SPP client to confirm installation of MO addition or update.</xsd:documentation>
- </xsd:annotation>
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element ref="sppError" minOccurs="0"/>
- <xsd:any namespace="##other" maxOccurs="unbounded" minOccurs="0"/>
- </xsd:sequence>
- <xsd:attribute ref="sppVersion" use="required"/>
- <xsd:attribute ref="sppStatus" use="required"/>
- <xsd:attribute ref="sessionID" use="required"/>
- <xsd:anyAttribute namespace="##other"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="sppExchangeComplete">
- <xsd:annotation>
- <xsd:documentation>SOAP method used by SPP server to end session.</xsd:documentation>
- </xsd:annotation>
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element ref="sppError" minOccurs="0"/>
- <xsd:any namespace="##other" maxOccurs="unbounded" minOccurs="0"/>
- </xsd:sequence>
- <xsd:attribute ref="sppVersion" use="required"/>
- <xsd:attribute ref="sppStatus" use="required"/>
- <xsd:attribute ref="sessionID" use="required"/>
- <xsd:anyAttribute namespace="##other"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="getCertificate">
- <xsd:annotation>
- <xsd:documentation>Command to mobile to initiate certificate enrollment or re-enrollment and is a container for metadata to enable enrollment.</xsd:documentation>
- </xsd:annotation>
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element name="enrollmentServerURI" type="httpsURIType">
- <xsd:annotation>
- <xsd:documentation>HTTPS URI of the server to be contacted to initiate certificate enrollment. The URI must contain an FQDN.</xsd:documentation>
- </xsd:annotation>
- </xsd:element>
- <xsd:element name="estUserID" minOccurs="0">
- <xsd:annotation>
- <xsd:documentation>Temporary userid used by an EST client to authenticate to the EST server using HTTP Digest authentication. This element must be used for initial certificate enrollment; its use is optional for certificate re-enrollment.</xsd:documentation>
- </xsd:annotation>
- <xsd:simpleType>
- <xsd:restriction base="xsd:string">
- <xsd:maxLength value="255"/>
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:element>
- <xsd:element name="estPassword" minOccurs="0">
- <xsd:annotation>
- <xsd:documentation>Temporary password used by an EST client to authenticate to the EST server using HTTP Digest authentication. This element must be used for initial certificate enrollment; its use is optional for certificate re-enrollment.</xsd:documentation>
- </xsd:annotation>
- <xsd:simpleType>
- <xsd:restriction base="xsd:base64Binary">
- <xsd:maxLength value="340"/>
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:element>
- <xsd:any namespace="##other" minOccurs="0" maxOccurs="unbounded">
- <xsd:annotation>
- <xsd:documentation>For vendor-specific extensions or future needs.</xsd:documentation>
- </xsd:annotation>
- </xsd:any>
- </xsd:sequence>
- <xsd:attribute name="enrollmentProtocol" use="required">
- <xsd:simpleType>
- <xsd:restriction base="xsd:string">
- <xsd:enumeration value="EST"/>
- <xsd:enumeration value="Other"/>
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:attribute>
- <xsd:anyAttribute namespace="##other"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="sppError">
- <xsd:annotation>
- <xsd:documentation>Error response.</xsd:documentation>
- </xsd:annotation>
- <xsd:complexType>
- <xsd:attribute name="errorCode" use="required">
- <xsd:simpleType>
- <xsd:restriction base="xsd:string">
- <xsd:enumeration value="SPP version not supported"/>
- <xsd:enumeration value="One or more mandatory MOs not supported"/>
- <xsd:enumeration value="Credentials cannot be provisioned at this time"/>
- <xsd:enumeration value="Remediation cannot be completed at this time"/>
- <xsd:enumeration value="Provisioning cannot be completed at this time"/>
- <xsd:enumeration value="Continue to use existing certificate"/>
- <xsd:enumeration value="Cookie invalid"/>
- <xsd:enumeration value="No corresponding web-browser-connection Session ID"/>
- <xsd:enumeration value="Permission denied"/>
- <xsd:enumeration value="Command failed"/>
- <xsd:enumeration value="MO addition or update failed"/>
- <xsd:enumeration value="Device full"/>
- <xsd:enumeration value="Bad management tree URI"/>
- <xsd:enumeration value="Requested entity too large"/>
- <xsd:enumeration value="Command not allowed"/>
- <xsd:enumeration value="Command not executed due to user"/>
- <xsd:enumeration value="Not found"/>
- <xsd:enumeration value="Other"/>
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:attribute>
- <xsd:anyAttribute namespace="##other"/>
- </xsd:complexType>
- </xsd:element>
-
- */
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/SPVerifier.java b/packages/Osu/src/com/android/hotspot2/osu/SPVerifier.java
deleted file mode 100644
index f193b6a4a7cd..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/SPVerifier.java
+++ /dev/null
@@ -1,330 +0,0 @@
-package com.android.hotspot2.osu;
-
-import android.util.Log;
-
-import com.android.anqp.HSIconFileElement;
-import com.android.anqp.I18Name;
-import com.android.anqp.IconInfo;
-import com.android.hotspot2.Utils;
-import com.android.hotspot2.asn1.Asn1Class;
-import com.android.hotspot2.asn1.Asn1Constructed;
-import com.android.hotspot2.asn1.Asn1Decoder;
-import com.android.hotspot2.asn1.Asn1Integer;
-import com.android.hotspot2.asn1.Asn1Object;
-import com.android.hotspot2.asn1.Asn1Octets;
-import com.android.hotspot2.asn1.Asn1Oid;
-import com.android.hotspot2.asn1.Asn1String;
-import com.android.hotspot2.asn1.OidMappings;
-import com.android.hotspot2.flow.OSUInfo;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.security.GeneralSecurityException;
-import java.security.MessageDigest;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-public class SPVerifier {
- public static final int OtherName = 0;
- public static final int DNSName = 2;
-
- private final OSUInfo mOSUInfo;
-
- public SPVerifier(OSUInfo osuInfo) {
- mOSUInfo = osuInfo;
- }
-
- /*
- SEQUENCE:
- [Context 0]:
- SEQUENCE:
- [Context 0]: -- LogotypeData
- SEQUENCE:
- SEQUENCE:
- SEQUENCE:
- IA5String='image/png'
- SEQUENCE:
- SEQUENCE:
- SEQUENCE:
- OID=2.16.840.1.101.3.4.2.1
- NULL
- OCTET_STRING= cf aa 74 a8 ad af 85 82 06 c8 f5 b5 bf ee 45 72 8a ee ea bd 47 ab 50 d3 62 0c 92 c1 53 c3 4c 6b
- SEQUENCE:
- IA5String='http://www.r2-testbed.wi-fi.org/icon_orange_zxx.png'
- SEQUENCE:
- INTEGER=4184
- INTEGER=-128
- INTEGER=61
- [Context 4]= 7a 78 78
- [Context 0]: -- LogotypeData
- SEQUENCE:
- SEQUENCE: -- LogotypeImage
- SEQUENCE: -- LogoTypeDetails
- IA5String='image/png'
- SEQUENCE:
- SEQUENCE: -- HashAlgAndValue
- SEQUENCE:
- OID=2.16.840.1.101.3.4.2.1
- NULL
- OCTET_STRING= cb 35 5c ba 7a 21 59 df 8e 0a e1 d8 9f a4 81 9e 41 8f af 58 0c 08 d6 28 7f 66 22 98 13 57 95 8d
- SEQUENCE:
- IA5String='http://www.r2-testbed.wi-fi.org/icon_orange_eng.png'
- SEQUENCE: -- LogotypeImageInfo
- INTEGER=11635
- INTEGER=-96
- INTEGER=76
- [Context 4]= 65 6e 67
- */
-
- private static class LogoTypeImage {
- private final String mMimeType;
- private final List<HashAlgAndValue> mHashes = new ArrayList<>();
- private final List<String> mURIs = new ArrayList<>();
- private final int mFileSize;
- private final int mXsize;
- private final int mYsize;
- private final String mLanguage;
-
- private LogoTypeImage(Asn1Constructed sequence) throws IOException {
- Iterator<Asn1Object> children = sequence.getChildren().iterator();
-
- Iterator<Asn1Object> logoTypeDetails =
- castObject(children.next(), Asn1Constructed.class).getChildren().iterator();
- mMimeType = castObject(logoTypeDetails.next(), Asn1String.class).getString();
-
- Asn1Constructed hashes = castObject(logoTypeDetails.next(), Asn1Constructed.class);
- for (Asn1Object hash : hashes.getChildren()) {
- mHashes.add(new HashAlgAndValue(castObject(hash, Asn1Constructed.class)));
- }
- Asn1Constructed urls = castObject(logoTypeDetails.next(), Asn1Constructed.class);
- for (Asn1Object url : urls.getChildren()) {
- mURIs.add(castObject(url, Asn1String.class).getString());
- }
-
- boolean imageInfoSet = false;
- int fileSize = -1;
- int xSize = -1;
- int ySize = -1;
- String language = null;
-
- if (children.hasNext()) {
- Iterator<Asn1Object> imageInfo =
- castObject(children.next(), Asn1Constructed.class).getChildren().iterator();
-
- Asn1Object first = imageInfo.next();
- if (first.getTag() == 0) {
- first = imageInfo.next(); // Ignore optional LogotypeImageType
- }
-
- fileSize = (int) castObject(first, Asn1Integer.class).getValue();
- xSize = (int) castObject(imageInfo.next(), Asn1Integer.class).getValue();
- ySize = (int) castObject(imageInfo.next(), Asn1Integer.class).getValue();
- imageInfoSet = true;
-
- if (imageInfo.hasNext()) {
- Asn1Object next = imageInfo.next();
- if (next.getTag() != 4) {
- next = imageInfo.hasNext() ? imageInfo.next() : null; // Skip resolution
- }
- if (next != null && next.getTag() == 4) {
- language = new String(castObject(next, Asn1Octets.class).getOctets(),
- StandardCharsets.US_ASCII);
- }
- }
- }
-
- if (imageInfoSet) {
- mFileSize = complement(fileSize);
- mXsize = complement(xSize);
- mYsize = complement(ySize);
- } else {
- mFileSize = mXsize = mYsize = -1;
- }
- mLanguage = language;
- }
-
- private boolean verify(OSUInfo osuInfo) throws GeneralSecurityException, IOException {
- IconInfo iconInfo = osuInfo.getIconInfo();
- HSIconFileElement iconData = osuInfo.getIconFileElement();
- if (!iconInfo.getIconType().equals(mMimeType) ||
- !iconInfo.getLanguage().equals(mLanguage) ||
- iconData.getIconData().length != mFileSize) {
- return false;
- }
- for (HashAlgAndValue hash : mHashes) {
- if (hash.getJCEName() != null) {
- MessageDigest digest = MessageDigest.getInstance(hash.getJCEName());
- byte[] computed = digest.digest(iconData.getIconData());
- if (!Arrays.equals(computed, hash.getHash())) {
- throw new IOException("Icon hash mismatch");
- } else {
- Log.d(OSUManager.TAG, "Icon verified with " + hash.getJCEName());
- return true;
- }
- }
- }
- return false;
- }
-
- @Override
- public String toString() {
- return "LogoTypeImage{" +
- "MimeType='" + mMimeType + '\'' +
- ", hashes=" + mHashes +
- ", URIs=" + mURIs +
- ", fileSize=" + mFileSize +
- ", xSize=" + mXsize +
- ", ySize=" + mYsize +
- ", language='" + mLanguage + '\'' +
- '}';
- }
- }
-
- private static class HashAlgAndValue {
- private final String mJCEName;
- private final byte[] mHash;
-
- private HashAlgAndValue(Asn1Constructed sequence) throws IOException {
- if (sequence.getChildren().size() != 2) {
- throw new IOException("Bad HashAlgAndValue");
- }
- Iterator<Asn1Object> children = sequence.getChildren().iterator();
- mJCEName = OidMappings.getJCEName(getFirstInner(children.next(), Asn1Oid.class));
- mHash = castObject(children.next(), Asn1Octets.class).getOctets();
- }
-
- public String getJCEName() {
- return mJCEName;
- }
-
- public byte[] getHash() {
- return mHash;
- }
-
- @Override
- public String toString() {
- return "HashAlgAndValue{" +
- "JCEName='" + mJCEName + '\'' +
- ", hash=" + Utils.toHex(mHash) +
- '}';
- }
- }
-
- private static int complement(int value) {
- return value >= 0 ? value : (~value) + 1;
- }
-
- private static <T extends Asn1Object> T castObject(Asn1Object object, Class<T> klass)
- throws IOException {
- if (object.getClass() != klass) {
- throw new IOException("Object is an " + object.getClass().getSimpleName() +
- " expected an " + klass.getSimpleName());
- }
- return klass.cast(object);
- }
-
- private static <T extends Asn1Object> T getFirstInner(Asn1Object container, Class<T> klass)
- throws IOException {
- if (container.getClass() != Asn1Constructed.class) {
- throw new IOException("Not a container");
- }
- Iterator<Asn1Object> children = container.getChildren().iterator();
- if (!children.hasNext()) {
- throw new IOException("No content");
- }
- return castObject(children.next(), klass);
- }
-
- public void verify(X509Certificate osuCert) throws IOException, GeneralSecurityException {
- if (osuCert == null) {
- throw new IOException("No OSU cert found");
- }
-
- checkName(castObject(getExtension(osuCert, OidMappings.IdCeSubjectAltName),
- Asn1Constructed.class));
-
- List<LogoTypeImage> logos = getImageData(getExtension(osuCert, OidMappings.IdPeLogotype));
- Log.d(OSUManager.TAG, "Logos: " + logos);
- for (LogoTypeImage logoTypeImage : logos) {
- if (logoTypeImage.verify(mOSUInfo)) {
- return;
- }
- }
- throw new IOException("Failed to match icon against any cert logo");
- }
-
- private static List<LogoTypeImage> getImageData(Asn1Object logoExtension) throws IOException {
- Asn1Constructed logo = castObject(logoExtension, Asn1Constructed.class);
- Asn1Constructed communityLogo = castObject(logo.getChildren().iterator().next(),
- Asn1Constructed.class);
- if (communityLogo.getTag() != 0) {
- throw new IOException("Expected tag [0] for communityLogos");
- }
-
- List<LogoTypeImage> images = new ArrayList<>();
- Asn1Constructed communityLogoSeq = castObject(communityLogo.getChildren().iterator().next(),
- Asn1Constructed.class);
- for (Asn1Object logoTypeData : communityLogoSeq.getChildren()) {
- if (logoTypeData.getTag() != 0) {
- throw new IOException("Expected tag [0] for LogotypeData");
- }
- for (Asn1Object logoTypeImage : castObject(logoTypeData.getChildren().iterator().next(),
- Asn1Constructed.class).getChildren()) {
- // only read the image SEQUENCE and skip any audio [1] tags
- if (logoTypeImage.getAsn1Class() == Asn1Class.Universal) {
- images.add(new LogoTypeImage(castObject(logoTypeImage, Asn1Constructed.class)));
- }
- }
- }
- return images;
- }
-
- private void checkName(Asn1Constructed altName) throws IOException {
- Map<String, I18Name> friendlyNames = new HashMap<>();
- for (Asn1Object name : altName.getChildren()) {
- if (name.getAsn1Class() == Asn1Class.Context && name.getTag() == OtherName) {
- Asn1Constructed otherName = (Asn1Constructed) name;
- Iterator<Asn1Object> children = otherName.getChildren().iterator();
- if (children.hasNext()) {
- Asn1Object oidObject = children.next();
- if (OidMappings.sIdWfaHotspotFriendlyName.equals(oidObject) &&
- children.hasNext()) {
- Asn1Constructed value = castObject(children.next(), Asn1Constructed.class);
- String text = castObject(value.getChildren().iterator().next(),
- Asn1String.class).getString();
- I18Name friendlyName = new I18Name(text);
- friendlyNames.put(friendlyName.getLanguage(), friendlyName);
- }
- }
- }
- }
- Log.d(OSUManager.TAG, "Friendly names: " + friendlyNames.values());
- for (I18Name osuName : mOSUInfo.getOSUProvider().getNames()) {
- I18Name friendlyName = friendlyNames.get(osuName.getLanguage());
- if (!osuName.equals(friendlyName)) {
- throw new IOException("Friendly name '" + osuName + " not in certificate");
- }
- }
- }
-
- private static Asn1Object getExtension(X509Certificate certificate, String extension)
- throws GeneralSecurityException, IOException {
- byte[] data = certificate.getExtensionValue(extension);
- if (data == null) {
- return null;
- }
- Asn1Octets octetString = (Asn1Octets) Asn1Decoder.decode(ByteBuffer.wrap(data)).
- iterator().next();
- Asn1Constructed sequence = castObject(Asn1Decoder.decode(
- ByteBuffer.wrap(octetString.getOctets())).iterator().next(),
- Asn1Constructed.class);
- Log.d(OSUManager.TAG, "Extension " + extension + ": " + sequence);
- return sequence;
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/UserInputListener.java b/packages/Osu/src/com/android/hotspot2/osu/UserInputListener.java
deleted file mode 100644
index ca30e3da0c0c..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/UserInputListener.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.android.hotspot2.osu;
-
-import android.net.Network;
-
-import java.net.URL;
-
-public interface UserInputListener {
- /**
- * Launch an appropriate application to handle user input and HTTP exchanges to the target
- * URL. Under normal circumstances this implies that a web-browser is started and pointed at
- * the target URL from which it is supposed to perform an initial HTTP GET operation.
- * This call must not block beyond the time it takes to launch the user agent, i.e. must return
- * well before the HTTP exchange terminates.
- * @param target A fully encoded URL to which to send an initial HTTP GET and then handle
- * subsequent HTTP exchanges.
- * @param endRedirect A URL to which the user agent will be redirected upon completion of
- * the HTTP exchange. This parameter is for informational purposes only
- * as the redirect to the URL is the responsibility of the remote server.
- */
- public void requestUserInput(URL target, Network network, URL endRedirect);
-
- /**
- * Notification that status of the OSU operation has changed. The implementation may choose to
- * return a string that will be passed to the user agent. Please note that the string is
- * passed as the payload of (the redirect) HTTP connection to the agent and must be formatted
- * appropriately (e.g. as well formed HTML).
- * Returning a null string on the initial status update of UserInputComplete or UserInputAborted
- * will cause the local "redirect" web-server to terminate and any further strings returned will
- * be ignored.
- * If programmatic termination of the user agent is desired, it should be initiated from within
- * the implementation of this method.
- * @param status
- * @param message
- * @return
- */
- public String operationStatus(String spIdentity, OSUOperationStatus status, String message);
-
- /**
- * Notify the user that a de-authentication event is imminent.
- * @param ess set to indicate that the de-authentication is for an ESS instead of a BSS
- * @param delay delay the number of seconds that the user will have to wait before
- * reassociating with the BSS or ESS.
- * @param url a URL to which to redirect the user
- */
- public void deAuthNotification(String spIdentity, boolean ess, int delay, URL url);
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/WiFiKeyManager.java b/packages/Osu/src/com/android/hotspot2/osu/WiFiKeyManager.java
deleted file mode 100644
index 54a3c4d90da9..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/WiFiKeyManager.java
+++ /dev/null
@@ -1,172 +0,0 @@
-package com.android.hotspot2.osu;
-
-import android.util.Log;
-
-import java.io.IOException;
-import java.net.Socket;
-import java.security.GeneralSecurityException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.Principal;
-import java.security.PrivateKey;
-import java.security.cert.Certificate;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.net.ssl.X509KeyManager;
-import javax.security.auth.x500.X500Principal;
-
-public class WiFiKeyManager implements X509KeyManager {
- private final KeyStore mKeyStore;
- private final Map<X500Principal, String[]> mAliases = new HashMap<>();
-
- public WiFiKeyManager(KeyStore keyStore) throws IOException {
- mKeyStore = keyStore;
- }
-
- public void enableClientAuth(List<String> issuerNames) throws GeneralSecurityException,
- IOException {
-
- Set<X500Principal> acceptedIssuers = new HashSet<>();
- for (String issuerName : issuerNames) {
- acceptedIssuers.add(new X500Principal(issuerName));
- }
-
- Enumeration<String> aliases = mKeyStore.aliases();
- while (aliases.hasMoreElements()) {
- String alias = aliases.nextElement();
- Certificate cert = mKeyStore.getCertificate(alias);
- if ((cert instanceof X509Certificate) && mKeyStore.getKey(alias, null) != null) {
- X509Certificate x509Certificate = (X509Certificate) cert;
- X500Principal issuer = x509Certificate.getIssuerX500Principal();
- if (acceptedIssuers.contains(issuer)) {
- mAliases.put(issuer, new String[]{alias, cert.getPublicKey().getAlgorithm()});
- }
- }
- }
-
- if (mAliases.isEmpty()) {
- throw new IOException("No aliases match requested issuers: " + issuerNames);
- }
- }
-
- private static class AliasEntry implements Comparable<AliasEntry> {
- private final int mPreference;
- private final String mAlias;
-
- private AliasEntry(int preference, String alias) {
- mPreference = preference;
- mAlias = alias;
- }
-
- public int getPreference() {
- return mPreference;
- }
-
- public String getAlias() {
- return mAlias;
- }
-
- @Override
- public int compareTo(AliasEntry other) {
- return Integer.compare(getPreference(), other.getPreference());
- }
- }
-
- @Override
- public String chooseClientAlias(String[] keyTypes, Principal[] issuers, Socket socket) {
-
- Map<String, Integer> keyPrefs = new HashMap<>(keyTypes.length);
- int pref = 0;
- for (String keyType : keyTypes) {
- keyPrefs.put(keyType, pref++);
- }
-
- List<AliasEntry> aliases = new ArrayList<>();
- if (issuers != null) {
- for (Principal issuer : issuers) {
- if (issuer instanceof X500Principal) {
- String[] aliasAndKey = mAliases.get((X500Principal) issuer);
- if (aliasAndKey != null) {
- Integer preference = keyPrefs.get(aliasAndKey[1]);
- if (preference != null) {
- aliases.add(new AliasEntry(preference, aliasAndKey[0]));
- }
- }
- }
- }
- } else {
- for (String[] aliasAndKey : mAliases.values()) {
- Integer preference = keyPrefs.get(aliasAndKey[1]);
- if (preference != null) {
- aliases.add(new AliasEntry(preference, aliasAndKey[0]));
- }
- }
- }
- Collections.sort(aliases);
- return aliases.isEmpty() ? null : aliases.get(0).getAlias();
- }
-
- @Override
- public String[] getClientAliases(String keyType, Principal[] issuers) {
- List<String> aliases = new ArrayList<>();
- if (issuers != null) {
- for (Principal issuer : issuers) {
- if (issuer instanceof X500Principal) {
- String[] aliasAndKey = mAliases.get((X500Principal) issuer);
- if (aliasAndKey != null) {
- aliases.add(aliasAndKey[0]);
- }
- }
- }
- } else {
- for (String[] aliasAndKey : mAliases.values()) {
- aliases.add(aliasAndKey[0]);
- }
- }
- return aliases.isEmpty() ? null : aliases.toArray(new String[aliases.size()]);
- }
-
- @Override
- public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String[] getServerAliases(String keyType, Principal[] issuers) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public X509Certificate[] getCertificateChain(String alias) {
- try {
- List<X509Certificate> certs = new ArrayList<>();
- for (Certificate certificate : mKeyStore.getCertificateChain(alias)) {
- if (certificate instanceof X509Certificate) {
- certs.add((X509Certificate) certificate);
- }
- }
- return certs.toArray(new X509Certificate[certs.size()]);
- } catch (KeyStoreException kse) {
- Log.w(OSUManager.TAG, "Failed to retrieve certificates: " + kse);
- return null;
- }
- }
-
- @Override
- public PrivateKey getPrivateKey(String alias) {
- try {
- return (PrivateKey) mKeyStore.getKey(alias, null);
- } catch (GeneralSecurityException gse) {
- Log.w(OSUManager.TAG, "Failed to retrieve private key: " + gse);
- return null;
- }
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/XMLParser.java b/packages/Osu/src/com/android/hotspot2/osu/XMLParser.java
deleted file mode 100644
index b23e5551575a..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/XMLParser.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package com.android.hotspot2.osu;
-
-import com.android.hotspot2.omadm.XMLNode;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
-
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-public class XMLParser extends DefaultHandler {
- private final SAXParser mParser;
- private final InputSource mInputSource;
-
- private XMLNode mRoot;
- private XMLNode mCurrent;
-
- public XMLParser(InputStream in) throws ParserConfigurationException, SAXException {
- mParser = SAXParserFactory.newInstance().newSAXParser();
- mInputSource = new InputSource(new BufferedReader(
- new InputStreamReader(in, StandardCharsets.UTF_8)));
- }
-
- public XMLNode getRoot() throws SAXException, IOException {
- mParser.parse(mInputSource, this);
- return mRoot;
- }
-
- @Override
- public void startElement(String uri, String localName, String qName, Attributes attributes)
- throws SAXException {
- XMLNode parent = mCurrent;
-
- mCurrent = new XMLNode(mCurrent, qName, attributes);
- //System.out.println("Added " + mCurrent.getTag() + ", atts " + mCurrent.getAttributes());
-
- if (mRoot == null)
- mRoot = mCurrent;
- else
- parent.addChild(mCurrent);
- }
-
- @Override
- public void endElement(String uri, String localName, String qName) throws SAXException {
- if (!qName.equals(mCurrent.getTag()))
- throw new SAXException("End tag '" + qName + "' doesn't match current node: " +
- mCurrent);
-
- try {
- mCurrent.close();
- } catch (IOException ioe) {
- throw new SAXException("Failed to close element", ioe);
- }
-
- mCurrent = mCurrent.getParent();
- }
-
- @Override
- public void characters(char[] ch, int start, int length) throws SAXException {
- mCurrent.addText(ch, start, length);
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/commands/BrowserURI.java b/packages/Osu/src/com/android/hotspot2/osu/commands/BrowserURI.java
deleted file mode 100644
index 137dbc933e3a..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/commands/BrowserURI.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.android.hotspot2.osu.commands;
-
-import com.android.hotspot2.omadm.XMLNode;
-
-/*
- <spp:sppPostDevDataResponse xmlns:spp="http://www.wi-fi.org/specifications/hotspot2dot0/v1.0/spp"
- spp:sessionID="D74A7B03005645DAA516191DEE77B94F" spp:sppStatus="OK"
- spp:sppVersion="1.0">
- <spp:exec>
- <spp:launchBrowserToURI>
- https://subscription-server.r2-testbed-rks.wi-fi.org:8443/web/ruckuswireles/home/-/onlinesignup/subscriberDetails?Credentials=USERNAME_PASSWORD&amp;SessionID=D74A7B03005645DAA516191DEE77B94F&amp;RedirectURI=http://127.0.0.1:12345/index.htm&amp;UpdateMethod=SPP-ClientInitiated
- </spp:launchBrowserToURI>
- </spp:exec>
- </spp:sppPostDevDataResponse>
- */
-
-public class BrowserURI implements OSUCommandData {
- private final String mURI;
-
- public BrowserURI(XMLNode commandNode) {
- mURI = commandNode.getText();
- }
-
- public String getURI() {
- return mURI;
- }
-
- @Override
- public String toString() {
- return "URI: " + mURI;
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/commands/ClientCertInfo.java b/packages/Osu/src/com/android/hotspot2/osu/commands/ClientCertInfo.java
deleted file mode 100644
index f877353b0e90..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/commands/ClientCertInfo.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package com.android.hotspot2.osu.commands;
-
-import com.android.hotspot2.omadm.OMAException;
-import com.android.hotspot2.omadm.XMLNode;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/*
-<xsd:element name="useClientCertTLS">
- <xsd:annotation>
- <xsd:documentation>Command to mobile to re-negotiate the TLS connection using a client certificate of the accepted type or Issuer to authenticate with the Subscription server.</xsd:documentation>
- </xsd:annotation>
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element name="providerIssuerName" minOccurs="0"
- maxOccurs="unbounded">
- <xsd:complexType>
- <xsd:attribute name="name" type="xsd:string">
- <xsd:annotation>
- <xsd:documentation>The issuer name of an acceptable provider-issued certificate. The text of this element is formatted in accordance with the Issuer Name field in RFC-3280. This element is present only when acceptProviderCerts is true.</xsd:documentation>
- </xsd:annotation>
- </xsd:attribute>
- <xsd:anyAttribute namespace="##other"/>
- </xsd:complexType>
- </xsd:element>
- <xsd:any namespace="##other" minOccurs="0"
- maxOccurs="unbounded"/>
- </xsd:sequence>
- <xsd:attribute name="acceptMfgCerts" type="xsd:boolean"
- use="optional" default="false">
- <xsd:annotation>
- <xsd:documentation>When this boolean is true, IEEE 802.1ar manufacturing certificates are acceptable for mobile device authentication.</xsd:documentation>
- </xsd:annotation>
- </xsd:attribute>
- <xsd:attribute name="acceptProviderCerts" type="xsd:boolean"
- use="optional" default="true">
- <xsd:annotation>
- <xsd:documentation>When this boolean is true, X509v3 certificates issued by providers identified in the providerIssuerName child element(s) are acceptable for mobile device authentication.</xsd:documentation>
- </xsd:annotation>
- </xsd:attribute>
- <xsd:anyAttribute namespace="##other"/>
- </xsd:complexType>
-</xsd:element>
- */
-
-public class ClientCertInfo implements OSUCommandData {
- private final boolean mAcceptMfgCerts;
- private final boolean mAcceptProviderCerts;
- /*
- * The issuer name of an acceptable provider-issued certificate.
- * The text of this element is formatted in accordance with the Issuer Name field in RFC-3280.
- * This element is present only when acceptProviderCerts is true.
- */
- private final List<String> mIssuerNames;
-
- public ClientCertInfo(XMLNode commandNode) throws OMAException {
- mAcceptMfgCerts = Boolean.parseBoolean(commandNode.getAttributeValue("acceptMfgCerts"));
- mAcceptProviderCerts =
- Boolean.parseBoolean(commandNode.getAttributeValue("acceptProviderCerts"));
-
- if (mAcceptMfgCerts) {
- mIssuerNames = new ArrayList<>();
- for (XMLNode node : commandNode.getChildren()) {
- if (node.getStrippedTag().equals("providerIssuerName")) {
- mIssuerNames.add(node.getAttributeValue("name"));
- }
- }
- } else {
- mIssuerNames = null;
- }
- }
-
- public boolean doesAcceptMfgCerts() {
- return mAcceptMfgCerts;
- }
-
- public boolean doesAcceptProviderCerts() {
- return mAcceptProviderCerts;
- }
-
- public List<String> getIssuerNames() {
- return mIssuerNames;
- }
-
- @Override
- public String toString() {
- return "ClientCertInfo{" +
- "acceptMfgCerts=" + mAcceptMfgCerts +
- ", acceptProviderCerts=" + mAcceptProviderCerts +
- ", issuerNames=" + mIssuerNames +
- '}';
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/commands/GetCertData.java b/packages/Osu/src/com/android/hotspot2/osu/commands/GetCertData.java
deleted file mode 100644
index 60a73fbf6a9d..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/commands/GetCertData.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package com.android.hotspot2.osu.commands;
-
-import android.util.Base64;
-
-import com.android.hotspot2.omadm.OMAException;
-import com.android.hotspot2.omadm.XMLNode;
-
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.Map;
-
-/*
- <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
- <env:Header/>
- <env:Body>
- <spp:sppPostDevDataResponse xmlns:spp="http://www.wi-fi.org/specifications/hotspot2dot0/v1.0/spp"
- spp:sessionID="A40103ACEDE94C45BA127A41239BD60F" spp:sppStatus="OK"
- spp:sppVersion="1.0">
- <spp:exec>
- <spp:getCertificate enrollmentProtocol="EST">
- <spp:enrollmentServerURI>https://osu-server.r2-testbed-rks.wi-fi.org:9446/.well-known/est
- </spp:enrollmentServerURI>
- <spp:estUserID>a88c4830-aafd-420b-b790-c08f457a0fa3</spp:estUserID>
- <spp:estPassword>cnVja3VzMTIzNA==</spp:estPassword>
- </spp:getCertificate>
- </spp:exec>
- </spp:sppPostDevDataResponse>
- </env:Body>
- </env:Envelope>
- */
-
-public class GetCertData implements OSUCommandData {
- private final String mProtocol;
- private final String mServer;
- private final String mUserName;
- private final byte[] mPassword;
-
- public GetCertData(XMLNode commandNode) throws OMAException {
- mProtocol = commandNode.getAttributeValue("enrollmentProtocol");
-
- Map<String, String> values = new HashMap<>(3);
- for (XMLNode node : commandNode.getChildren()) {
- values.put(node.getStrippedTag(), node.getText());
- }
-
- mServer = values.get("enrollmentserveruri");
- mUserName = values.get("estuserid");
- mPassword = Base64.decode(values.get("estpassword"), Base64.DEFAULT);
- }
-
- public String getProtocol() {
- return mProtocol;
- }
-
- public String getServer() {
- return mServer;
- }
-
- public String getUserName() {
- return mUserName;
- }
-
- public byte[] getPassword() {
- return mPassword;
- }
-
- @Override
- public String toString() {
- return "GetCertData " +
- "protocol='" + mProtocol + '\'' +
- ", server='" + mServer + '\'' +
- ", userName='" + mUserName + '\'' +
- ", password='" + new String(mPassword, StandardCharsets.ISO_8859_1) + '\'';
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/commands/MOData.java b/packages/Osu/src/com/android/hotspot2/osu/commands/MOData.java
deleted file mode 100644
index aa83db097a44..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/commands/MOData.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.android.hotspot2.osu.commands;
-
-import android.net.wifi.PasspointManagementObjectDefinition;
-
-import com.android.hotspot2.omadm.MOTree;
-import com.android.hotspot2.omadm.OMAConstants;
-import com.android.hotspot2.omadm.OMAParser;
-import com.android.hotspot2.omadm.XMLNode;
-
-import org.xml.sax.SAXException;
-
-import java.io.IOException;
-
-public class MOData implements OSUCommandData {
- private final String mBaseURI;
- private final String mURN;
- private final MOTree mMOTree;
-
- public MOData(XMLNode root) {
- mBaseURI = root.getAttributeValue("spp:managementTreeURI");
- mURN = root.getAttributeValue("spp:moURN");
- mMOTree = root.getMOTree();
- }
-
- public String getBaseURI() {
- return mBaseURI;
- }
-
- public String getURN() {
- return mURN;
- }
-
- public MOTree getMOTree() {
- return mMOTree;
- }
-
- @Override
- public String toString() {
- return "Base URI: " + mBaseURI + ", MO: " + mMOTree;
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/commands/MOURN.java b/packages/Osu/src/com/android/hotspot2/osu/commands/MOURN.java
deleted file mode 100644
index 46394ef834c4..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/commands/MOURN.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.android.hotspot2.osu.commands;
-
-/*
-<xsd:element name="uploadMO" maxOccurs="unbounded">
- <xsd:annotation>
- <xsd:documentation>Command to mobile to upload the MO named in the moURN attribute to the SPP server.</xsd:documentation>
- </xsd:annotation>
- <xsd:complexType>
- <xsd:attribute ref="moURN"/>
- </xsd:complexType>
-</xsd:element>
- */
-
-import com.android.hotspot2.omadm.XMLNode;
-
-public class MOURN implements OSUCommandData {
- private final String mURN;
-
- public MOURN(XMLNode root) {
- mURN = root.getAttributeValue("spp:moURN");
- }
-
- public String getURN() {
- return mURN;
- }
-
- @Override
- public String toString() {
- return "MOURN{" +
- "URN='" + mURN + '\'' +
- '}';
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/commands/OSUCommandData.java b/packages/Osu/src/com/android/hotspot2/osu/commands/OSUCommandData.java
deleted file mode 100644
index 06f81bf06694..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/commands/OSUCommandData.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.android.hotspot2.osu.commands;
-
-/**
- * Marker interface
- */
-public interface OSUCommandData {
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/service/RedirectListener.java b/packages/Osu/src/com/android/hotspot2/osu/service/RedirectListener.java
deleted file mode 100644
index 105a96dddda3..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/service/RedirectListener.java
+++ /dev/null
@@ -1,206 +0,0 @@
-package com.android.hotspot2.osu.service;
-
-import android.util.Log;
-
-import com.android.hotspot2.flow.PlatformAdapter;
-import com.android.hotspot2.osu.OSUOperationStatus;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.net.InetAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.util.Random;
-
-public class RedirectListener extends Thread {
- private static final long ThreadTimeout = 3000L;
- private static final long UserTimeout = 3600000L;
- private static final int MaxRetry = 5;
- private static final String TAG = "OSULSN";
-
- private static final String HTTPResponseHeader =
- "HTTP/1.1 304 Not Modified\r\n" +
- "Server: dummy\r\n" +
- "Keep-Alive: timeout=500, max=5\r\n\r\n";
-
- private static final String GoodBye =
- "<html>" +
- "<head><title>Goodbye</title></head>" +
- "<body>" +
- "<h3>Killing browser...</h3>" +
- "</body>" +
- "</html>\r\n";
-
- private final PlatformAdapter mPlatformAdapter;
- private final String mSpName;
- private final ServerSocket mServerSocket;
- private final String mPath;
- private final URL mURL;
- private final Object mLock = new Object();
-
- private boolean mListening;
- private OSUOperationStatus mUserStatus;
- private volatile boolean mAborted;
-
- public RedirectListener(PlatformAdapter platformAdapter, String spName) throws IOException {
- mPlatformAdapter = platformAdapter;
- mSpName = spName;
- mServerSocket = new ServerSocket(0, 5, InetAddress.getLocalHost());
- Random rnd = new Random(System.currentTimeMillis());
- mPath = "rnd" + Integer.toString(Math.abs(rnd.nextInt()), Character.MAX_RADIX);
- mURL = new URL("http", mServerSocket.getInetAddress().getHostAddress(),
- mServerSocket.getLocalPort(), mPath);
-
- Log.d(TAG, "Redirect URL: " + mURL);
- setName("HS20-Redirect-Listener");
- setDaemon(true);
- }
-
- public void startService() throws IOException {
- start();
- synchronized (mLock) {
- long bail = System.currentTimeMillis() + ThreadTimeout;
- long remainder = ThreadTimeout;
- while (remainder > 0 && !mListening) {
- try {
- mLock.wait(remainder);
- } catch (InterruptedException ie) {
- /**/
- }
- if (mListening) {
- break;
- }
- remainder = bail - System.currentTimeMillis();
- }
- if (!mListening) {
- throw new IOException("Failed to start listener");
- } else {
- Log.d(TAG, "OSU Redirect listener running");
- }
- }
- }
-
- public boolean waitForUser() {
- boolean success;
- synchronized (mLock) {
- long bail = System.currentTimeMillis() + UserTimeout;
- long remainder = UserTimeout;
- while (remainder > 0 && mUserStatus == null) {
- try {
- mLock.wait(remainder);
- } catch (InterruptedException ie) {
- /**/
- }
- if (mUserStatus != null) {
- break;
- }
- remainder = bail - System.currentTimeMillis();
- }
- success = mUserStatus == OSUOperationStatus.UserInputComplete;
- }
- abort();
- return success;
- }
-
- public void abort() {
- try {
- synchronized (mLock) {
- mUserStatus = OSUOperationStatus.UserInputAborted;
- mLock.notifyAll();
- }
- mAborted = true;
- mServerSocket.close();
- } catch (IOException ioe) {
- /**/
- }
- }
-
- public URL getURL() {
- return mURL;
- }
-
- @Override
- public void run() {
- int count = 0;
- synchronized (mLock) {
- mListening = true;
- mLock.notifyAll();
- }
-
- boolean terminate = false;
-
- for (; ; ) {
- count++;
- try (Socket instance = mServerSocket.accept()) {
- try (BufferedReader in = new BufferedReader(
- new InputStreamReader(instance.getInputStream(), StandardCharsets.UTF_8))) {
- boolean detected = false;
- StringBuilder sb = new StringBuilder();
- String s;
- while ((s = in.readLine()) != null) {
- sb.append(s).append('\n');
- if (!detected && s.startsWith("GET")) {
- String[] segments = s.split(" ");
- if (segments.length == 3 &&
- segments[2].startsWith("HTTP/") &&
- segments[1].regionMatches(1, mPath, 0, mPath.length())) {
- detected = true;
- }
- }
- if (s.length() == 0) {
- break;
- }
- }
- Log.d(TAG, "Redirect receive: " + sb);
- String response = null;
- if (detected) {
- response = status(OSUOperationStatus.UserInputComplete);
- if (response == null) {
- response = GoodBye;
- terminate = true;
- }
- }
- try (BufferedWriter out = new BufferedWriter(
- new OutputStreamWriter(instance.getOutputStream(),
- StandardCharsets.UTF_8))) {
-
- out.write(HTTPResponseHeader);
- if (response != null) {
- out.write(response);
- }
- }
- if (terminate) {
- break;
- } else if (count > MaxRetry) {
- status(OSUOperationStatus.UserInputAborted);
- break;
- }
- }
- } catch (IOException ioe) {
- if (mAborted) {
- return;
- } else if (count > MaxRetry) {
- status(OSUOperationStatus.UserInputAborted);
- break;
- }
- }
- }
- }
-
- private String status(OSUOperationStatus status) {
- Log.d(TAG, "User input status: " + status);
- synchronized (mLock) {
- mUserStatus = status;
- mLock.notifyAll();
- }
- String message = (status == OSUOperationStatus.UserInputAborted) ?
- "Browser closed" : null;
-
- return mPlatformAdapter.notifyUser(status, message, mSpName);
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/osu/service/RemediationHandler.java b/packages/Osu/src/com/android/hotspot2/osu/service/RemediationHandler.java
deleted file mode 100644
index e1c6af66a805..000000000000
--- a/packages/Osu/src/com/android/hotspot2/osu/service/RemediationHandler.java
+++ /dev/null
@@ -1,585 +0,0 @@
-package com.android.hotspot2.osu.service;
-
-import android.app.AlarmManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.net.Network;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.hotspot2.PasspointMatch;
-import com.android.hotspot2.Utils;
-import com.android.hotspot2.flow.FlowService;
-import com.android.hotspot2.omadm.MOManager;
-import com.android.hotspot2.omadm.MOTree;
-import com.android.hotspot2.omadm.OMAConstants;
-import com.android.hotspot2.omadm.OMAException;
-import com.android.hotspot2.omadm.OMAParser;
-import com.android.hotspot2.osu.OSUManager;
-import com.android.hotspot2.pps.HomeSP;
-import com.android.hotspot2.pps.UpdateInfo;
-import com.android.hotspot2.flow.IFlowService;
-
-import org.xml.sax.SAXException;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import static com.android.hotspot2.pps.UpdateInfo.UpdateRestriction;
-
-public class RemediationHandler implements AlarmManager.OnAlarmListener {
- private final Context mContext;
- private final File mStateFile;
-
- private final Map<String, PasspointConfig> mPasspointConfigs = new HashMap<>();
- private final Map<String, List<RemediationEvent>> mUpdates = new HashMap<>();
- private final LinkedList<PendingUpdate> mOutstanding = new LinkedList<>();
-
- private WifiInfo mActiveWifiInfo;
- private PasspointConfig mActivePasspointConfig;
-
- public RemediationHandler(Context context, File stateFile) {
- mContext = context;
- mStateFile = stateFile;
- Log.d(OSUManager.TAG, "State file: " + stateFile);
- reloadAll(context, mPasspointConfigs, stateFile, mUpdates);
- mActivePasspointConfig = getActivePasspointConfig();
- calculateTimeout();
- }
-
- /**
- * Network configs change: Re-evaluate set of HomeSPs and recalculate next time-out.
- */
- public void networkConfigChange() {
- Log.d(OSUManager.TAG, "Networks changed");
- mPasspointConfigs.clear();
- mUpdates.clear();
- Iterator<PendingUpdate> updates = mOutstanding.iterator();
- while (updates.hasNext()) {
- PendingUpdate update = updates.next();
- if (!update.isWnmBased()) {
- updates.remove();
- }
- }
- reloadAll(mContext, mPasspointConfigs, mStateFile, mUpdates);
- calculateTimeout();
- }
-
- /**
- * Connected to new network: Try to rematch any outstanding remediation entries to the new
- * config.
- */
- public void newConnection(WifiInfo newNetwork) {
- mActivePasspointConfig = newNetwork != null ? getActivePasspointConfig() : null;
- if (mActivePasspointConfig != null) {
- Log.d(OSUManager.TAG, "New connection to "
- + mActivePasspointConfig.getHomeSP().getFQDN());
- } else {
- Log.d(OSUManager.TAG, "No passpoint connection");
- return;
- }
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- WifiInfo wifiInfo = wifiManager.getConnectionInfo();
- Network network = wifiManager.getCurrentNetwork();
-
- Iterator<PendingUpdate> updates = mOutstanding.iterator();
- while (updates.hasNext()) {
- PendingUpdate update = updates.next();
- try {
- if (update.matches(wifiInfo, mActivePasspointConfig.getHomeSP())) {
- update.remediate(network);
- updates.remove();
- } else if (update.isWnmBased()) {
- Log.d(OSUManager.TAG, "WNM sender mismatches with BSS, cancelling remediation");
- // Drop WNM update if it doesn't match the connected network
- updates.remove();
- }
- } catch (IOException ioe) {
- updates.remove();
- }
- }
- }
-
- /**
- * Remediation timer fired: Iterate HomeSP and either pass on to remediation if there is a
- * policy match or put on hold-off queue until a new network connection is made.
- */
- @Override
- public void onAlarm() {
- Log.d(OSUManager.TAG, "Remediation timer");
- calculateTimeout();
- }
-
- /**
- * Remediation frame received, either pass on to pre-remediation check right away or await
- * network connection.
- */
- public void wnmReceived(long bssid, String url) {
- PendingUpdate update = new PendingUpdate(bssid, url);
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- WifiInfo wifiInfo = wifiManager.getConnectionInfo();
- try {
- if (mActivePasspointConfig == null) {
- Log.d(OSUManager.TAG, String.format("WNM remediation frame '%s' through %012x " +
- "received, adding to outstanding remediations", url, bssid));
- mOutstanding.addFirst(new PendingUpdate(bssid, url));
- } else if (update.matches(wifiInfo, mActivePasspointConfig.getHomeSP())) {
- Log.d(OSUManager.TAG, String.format("WNM remediation frame '%s' through %012x " +
- "received, remediating now", url, bssid));
- update.remediate(wifiManager.getCurrentNetwork());
- } else {
- Log.w(OSUManager.TAG, String.format("WNM remediation frame '%s' through %012x " +
- "does not meet restriction", url, bssid));
- }
- } catch (IOException ioe) {
- Log.w(OSUManager.TAG, "Failed to remediate from WNM: " + ioe);
- }
- }
-
- /**
- * Callback to indicate that remediation has succeeded.
- * @param fqdn The SPs FQDN
- * @param policy set if this update was a policy update rather than a subscription update.
- */
- public void remediationDone(String fqdn, boolean policy) {
- Log.d(OSUManager.TAG, "Remediation complete for " + fqdn);
- long now = System.currentTimeMillis();
- List<RemediationEvent> events = mUpdates.get(fqdn);
- if (events == null) {
- events = new ArrayList<>();
- events.add(new RemediationEvent(fqdn, policy, now));
- mUpdates.put(fqdn, events);
- } else {
- Iterator<RemediationEvent> eventsIterator = events.iterator();
- while (eventsIterator.hasNext()) {
- RemediationEvent event = eventsIterator.next();
- if (event.isPolicy() == policy) {
- eventsIterator.remove();
- }
- }
- events.add(new RemediationEvent(fqdn, policy, now));
- }
- saveUpdates(mStateFile, mUpdates);
- }
-
- public String getCurrentSpName() {
- PasspointConfig config = getActivePasspointConfig();
- return config != null ? config.getHomeSP().getFriendlyName() : "unknown";
- }
-
- private PasspointConfig getActivePasspointConfig() {
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- mActiveWifiInfo = wifiManager.getConnectionInfo();
- if (mActiveWifiInfo == null) {
- return null;
- }
-
- for (PasspointConfig passpointConfig : mPasspointConfigs.values()) {
- if (passpointConfig.getWifiConfiguration().networkId
- == mActiveWifiInfo.getNetworkId()) {
- return passpointConfig;
- }
- }
- return null;
- }
-
- private void calculateTimeout() {
- long now = System.currentTimeMillis();
- long next = Long.MAX_VALUE;
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- Network network = wifiManager.getCurrentNetwork();
-
- boolean newBaseTimes = false;
- for (PasspointConfig passpointConfig : mPasspointConfigs.values()) {
- HomeSP homeSP = passpointConfig.getHomeSP();
-
- for (boolean policy : new boolean[] {false, true}) {
- Long expiry = getNextUpdate(homeSP, policy, now);
- Log.d(OSUManager.TAG, "Next remediation for " + homeSP.getFQDN()
- + (policy ? "/policy" : "/subscription")
- + " is " + toExpiry(expiry));
- if (expiry == null || inProgress(homeSP, policy)) {
- continue;
- } else if (expiry < 0) {
- next = now - expiry;
- newBaseTimes = true;
- continue;
- }
-
- if (expiry <= now) {
- String uri = policy ? homeSP.getPolicy().getPolicyUpdate().getURI()
- : homeSP.getSubscriptionUpdate().getURI();
- PendingUpdate update = new PendingUpdate(homeSP, uri, policy);
- try {
- if (update.matches(mActiveWifiInfo, homeSP)) {
- update.remediate(network);
- } else {
- Log.d(OSUManager.TAG, "Remediation for "
- + homeSP.getFQDN() + " pending");
- mOutstanding.addLast(update);
- }
- } catch (IOException ioe) {
- Log.w(OSUManager.TAG, "Failed to remediate "
- + homeSP.getFQDN() + ": " + ioe);
- }
- } else {
- next = Math.min(next, expiry);
- }
- }
- }
- if (newBaseTimes) {
- saveUpdates(mStateFile, mUpdates);
- }
- Log.d(OSUManager.TAG, "Next time-out at " + toExpiry(next));
- AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- alarmManager.set(AlarmManager.RTC, next, "osu-remediation", this, null);
- }
-
- private static String toExpiry(Long time) {
- if (time == null) {
- return "n/a";
- } else if (time < 0) {
- return Utils.toHMS(-time) + " from now";
- } else if (time > 0xffffffffffffL) {
- return "infinity";
- } else {
- return Utils.toUTCString(time);
- }
- }
-
- /**
- * Get the next update time for the homeSP subscription or policy entry. Automatically add a
- * wall time reference if it is missing.
- * @param homeSP The HomeSP to check
- * @param policy policy or subscription object.
- * @return -interval if no wall time ref, null if n/a, otherwise wall time of next update.
- */
- private Long getNextUpdate(HomeSP homeSP, boolean policy, long now) {
- long interval;
- if (policy) {
- interval = homeSP.getPolicy().getPolicyUpdate().getInterval();
- } else if (homeSP.getSubscriptionUpdate() != null) {
- interval = homeSP.getSubscriptionUpdate().getInterval();
- } else {
- return null;
- }
- if (interval < 0) {
- return null;
- }
-
- RemediationEvent event = getMatchingEvent(mUpdates.get(homeSP.getFQDN()), policy);
- if (event == null) {
- List<RemediationEvent> events = mUpdates.get(homeSP.getFQDN());
- if (events == null) {
- events = new ArrayList<>();
- mUpdates.put(homeSP.getFQDN(), events);
- }
- events.add(new RemediationEvent(homeSP.getFQDN(), policy, now));
- return -interval;
- }
- return event.getLastUpdate() + interval;
- }
-
- private boolean inProgress(HomeSP homeSP, boolean policy) {
- Iterator<PendingUpdate> updates = mOutstanding.iterator();
- while (updates.hasNext()) {
- PendingUpdate update = updates.next();
- if (update.getHomeSP() != null
- && update.getHomeSP().getFQDN().equals(homeSP.getFQDN())) {
- if (update.isPolicy() && !policy) {
- // Subscription updates takes precedence over policy updates
- updates.remove();
- return false;
- } else {
- return true;
- }
- }
- }
- return false;
- }
-
- private static RemediationEvent getMatchingEvent(
- List<RemediationEvent> events, boolean policy) {
- if (events == null) {
- return null;
- }
- for (RemediationEvent event : events) {
- if (event.isPolicy() == policy) {
- return event;
- }
- }
- return null;
- }
-
- private static void reloadAll(Context context, Map<String, PasspointConfig> passpointConfigs,
- File stateFile, Map<String, List<RemediationEvent>> updates) {
-
- loadAllSps(context, passpointConfigs);
- try {
- loadUpdates(stateFile, updates);
- } catch (IOException ioe) {
- Log.w(OSUManager.TAG, "Failed to load updates file: " + ioe);
- }
-
- boolean change = false;
- Iterator<Map.Entry<String, List<RemediationEvent>>> events = updates.entrySet().iterator();
- while (events.hasNext()) {
- Map.Entry<String, List<RemediationEvent>> event = events.next();
- if (!passpointConfigs.containsKey(event.getKey())) {
- events.remove();
- change = true;
- }
- }
- Log.d(OSUManager.TAG, "Updates: " + updates);
- if (change) {
- saveUpdates(stateFile, updates);
- }
- }
-
- private static void loadAllSps(Context context, Map<String, PasspointConfig> passpointConfigs) {
- WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
- List<WifiConfiguration> configs = wifiManager.getPrivilegedConfiguredNetworks();
- if (configs == null) {
- return;
- }
- int count = 0;
- for (WifiConfiguration config : configs) {
- String moTree = config.getMoTree();
- if (moTree != null) {
- try {
- passpointConfigs.put(config.FQDN, new PasspointConfig(config));
- count++;
- } catch (IOException | SAXException e) {
- Log.w(OSUManager.TAG, "Failed to parse MO: " + e);
- }
- }
- }
- Log.d(OSUManager.TAG, "Loaded " + count + " SPs");
- }
-
- private static void loadUpdates(File file, Map<String, List<RemediationEvent>> updates)
- throws IOException {
- try (BufferedReader in = new BufferedReader(new FileReader(file))) {
- String line;
- while ((line = in.readLine()) != null) {
- try {
- RemediationEvent event = new RemediationEvent(line);
- List<RemediationEvent> events = updates.get(event.getFqdn());
- if (events == null) {
- events = new ArrayList<>();
- updates.put(event.getFqdn(), events);
- }
- events.add(event);
- } catch (IOException | NumberFormatException e) {
- Log.w(OSUManager.TAG, "Bad line in " + file + ": '" + line + "': " + e);
- }
- }
- }
- }
-
- private static void saveUpdates(File file, Map<String, List<RemediationEvent>> updates) {
- try (BufferedWriter out = new BufferedWriter(new FileWriter(file, false))) {
- for (List<RemediationEvent> events : updates.values()) {
- for (RemediationEvent event : events) {
- Log.d(OSUManager.TAG, "Writing wall time ref for " + event);
- out.write(event.toString());
- out.newLine();
- }
- }
- } catch (IOException ioe) {
- Log.w(OSUManager.TAG, "Failed to save update state: " + ioe);
- }
- }
-
- private static class PasspointConfig {
- private final WifiConfiguration mWifiConfiguration;
- private final MOTree mMOTree;
- private final HomeSP mHomeSP;
-
- private PasspointConfig(WifiConfiguration config) throws IOException, SAXException {
- mWifiConfiguration = config;
- OMAParser omaParser = new OMAParser();
- mMOTree = omaParser.parse(config.getMoTree(), OMAConstants.PPS_URN);
- List<HomeSP> spList = MOManager.buildSPs(mMOTree);
- if (spList.size() != 1) {
- throw new OMAException("Expected exactly one HomeSP, got " + spList.size());
- }
- mHomeSP = spList.iterator().next();
- }
-
- public WifiConfiguration getWifiConfiguration() {
- return mWifiConfiguration;
- }
-
- public HomeSP getHomeSP() {
- return mHomeSP;
- }
-
- public MOTree getMOTree() {
- return mMOTree;
- }
- }
-
- private static class RemediationEvent {
- private final String mFqdn;
- private final boolean mPolicy;
- private final long mLastUpdate;
-
- private RemediationEvent(String value) throws IOException {
- String[] segments = value.split(" ");
- if (segments.length != 3) {
- throw new IOException("Bad line: '" + value + "'");
- }
- mFqdn = segments[0];
- mPolicy = segments[1].equals("1");
- mLastUpdate = Long.parseLong(segments[2]);
- }
-
- private RemediationEvent(String fqdn, boolean policy, long now) {
- mFqdn = fqdn;
- mPolicy = policy;
- mLastUpdate = now;
- }
-
- public String getFqdn() {
- return mFqdn;
- }
-
- public boolean isPolicy() {
- return mPolicy;
- }
-
- public long getLastUpdate() {
- return mLastUpdate;
- }
-
- @Override
- public String toString() {
- return String.format("%s %c %d", mFqdn, mPolicy ? '1' : '0', mLastUpdate);
- }
- }
-
- private class PendingUpdate {
- private final HomeSP mHomeSP; // For time based updates
- private final long mBssid; // WNM based
- private final String mUrl; // WNM based
- private final boolean mPolicy;
-
- private PendingUpdate(HomeSP homeSP, String url, boolean policy) {
- mHomeSP = homeSP;
- mPolicy = policy;
- mBssid = 0L;
- mUrl = url;
- }
-
- private PendingUpdate(long bssid, String url) {
- mBssid = bssid;
- mUrl = url;
- mHomeSP = null;
- mPolicy = false;
- }
-
- private boolean matches(WifiInfo wifiInfo, HomeSP activeSP) throws IOException {
- if (mHomeSP == null) {
- // WNM initiated remediation, HomeSP restriction
- Log.d(OSUManager.TAG, String.format("Checking applicability of %s to %012x\n",
- wifiInfo != null ? wifiInfo.getBSSID() : "-", mBssid));
- return wifiInfo != null
- && Utils.parseMac(wifiInfo.getBSSID()) == mBssid
- && passesRestriction(activeSP); // !!! b/28600780
- } else {
- return passesRestriction(mHomeSP);
- }
- }
-
- private boolean passesRestriction(HomeSP restrictingSP)
- throws IOException {
- UpdateInfo updateInfo;
- if (mPolicy) {
- if (restrictingSP.getPolicy() == null) {
- throw new IOException("No policy object");
- }
- updateInfo = restrictingSP.getPolicy().getPolicyUpdate();
- } else {
- updateInfo = restrictingSP.getSubscriptionUpdate();
- }
-
- if (updateInfo.getUpdateRestriction() == UpdateRestriction.Unrestricted) {
- return true;
- }
-
- PasspointMatch match = matchProviderWithCurrentNetwork(restrictingSP.getFQDN());
- Log.d(OSUManager.TAG, "Current match for '" + restrictingSP.getFQDN()
- + "' is " + match + ", restriction " + updateInfo.getUpdateRestriction());
- return match == PasspointMatch.HomeProvider
- || (match == PasspointMatch.RoamingProvider
- && updateInfo.getUpdateRestriction() == UpdateRestriction.RoamingPartner);
- }
-
- private void remediate(Network network) {
- RemediationHandler.this.remediate(mHomeSP != null ? mHomeSP.getFQDN() : null,
- mUrl, mPolicy, network);
- }
-
- private HomeSP getHomeSP() {
- return mHomeSP;
- }
-
- private boolean isPolicy() {
- return mPolicy;
- }
-
- private boolean isWnmBased() {
- return mHomeSP == null;
- }
-
- private PasspointMatch matchProviderWithCurrentNetwork(String fqdn) {
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- return Utils.mapEnum(wifiManager.matchProviderWithCurrentNetwork(fqdn),
- PasspointMatch.class);
- }
- }
-
- /**
- * Initiate remediation
- * @param spFqdn The FQDN of the current SP, not set for WNM based remediation
- * @param url The URL of the remediation server
- * @param policy Set if this is a policy update rather than a subscription update
- * @param network The network to use for remediation
- */
- private void remediate(final String spFqdn, final String url,
- final boolean policy, final Network network) {
- mContext.bindService(new Intent(mContext, FlowService.class), new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- try {
- IFlowService fs = IFlowService.Stub.asInterface(service);
- fs.remediate(spFqdn, url, policy, network);
- } catch (RemoteException re) {
- Log.e(OSUManager.TAG, "Caught re: " + re);
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
-
- }
- }, Context.BIND_AUTO_CREATE);
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/pps/Credential.java b/packages/Osu/src/com/android/hotspot2/pps/Credential.java
deleted file mode 100644
index 15f0dcf4fd50..000000000000
--- a/packages/Osu/src/com/android/hotspot2/pps/Credential.java
+++ /dev/null
@@ -1,252 +0,0 @@
-package com.android.hotspot2.pps;
-
-import android.text.TextUtils;
-import android.util.Base64;
-
-import com.android.anqp.eap.EAPMethod;
-import com.android.hotspot2.IMSIParameter;
-import com.android.hotspot2.Utils;
-import com.android.hotspot2.omadm.OMAException;
-
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-
-public class Credential {
- public enum CertType {IEEE, x509v3}
-
- public static final String CertTypeX509 = "x509v3";
- public static final String CertTypeIEEE = "802.1ar";
-
- private final long mCtime;
- private final long mExpTime;
- private final String mRealm;
- private final boolean mCheckAAACert;
-
- private final String mUserName;
- private final String mPassword;
- private final boolean mDisregardPassword;
- private final boolean mMachineManaged;
- private final String mSTokenApp;
- private final boolean mShare;
- private final EAPMethod mEAPMethod;
-
- private final CertType mCertType;
- private final byte[] mFingerPrint;
-
- private final IMSIParameter mImsi;
-
- public Credential(long ctime, long expTime, String realm, boolean checkAAACert,
- EAPMethod eapMethod, String userName, String password,
- boolean machineManaged, String stApp, boolean share) {
- mCtime = ctime;
- mExpTime = expTime;
- mRealm = realm;
- mCheckAAACert = checkAAACert;
- mEAPMethod = eapMethod;
- mUserName = userName;
-
- if (!TextUtils.isEmpty(password)) {
- byte[] pwOctets = Base64.decode(password, Base64.DEFAULT);
- mPassword = new String(pwOctets, StandardCharsets.UTF_8);
- } else {
- mPassword = null;
- }
- mDisregardPassword = false;
-
- mMachineManaged = machineManaged;
- mSTokenApp = stApp;
- mShare = share;
-
- mCertType = null;
- mFingerPrint = null;
-
- mImsi = null;
- }
-
- public Credential(long ctime, long expTime, String realm, boolean checkAAACert,
- EAPMethod eapMethod, Credential.CertType certType, byte[] fingerPrint) {
- mCtime = ctime;
- mExpTime = expTime;
- mRealm = realm;
- mCheckAAACert = checkAAACert;
- mEAPMethod = eapMethod;
- mCertType = certType;
- mFingerPrint = fingerPrint;
-
- mUserName = null;
- mPassword = null;
- mDisregardPassword = false;
- mMachineManaged = false;
- mSTokenApp = null;
- mShare = false;
-
- mImsi = null;
- }
-
- public Credential(long ctime, long expTime, String realm, boolean checkAAACert,
- EAPMethod eapMethod, IMSIParameter imsi) {
- mCtime = ctime;
- mExpTime = expTime;
- mRealm = realm;
- mCheckAAACert = checkAAACert;
- mEAPMethod = eapMethod;
- mImsi = imsi;
-
- mCertType = null;
- mFingerPrint = null;
-
- mUserName = null;
- mPassword = null;
- mDisregardPassword = false;
- mMachineManaged = false;
- mSTokenApp = null;
- mShare = false;
- }
-
- public Credential(Credential other, String password) {
- mCtime = other.mCtime;
- mExpTime = other.mExpTime;
- mRealm = other.mRealm;
- mCheckAAACert = other.mCheckAAACert;
- mUserName = other.mUserName;
- mPassword = password;
- mDisregardPassword = other.mDisregardPassword;
- mMachineManaged = other.mMachineManaged;
- mSTokenApp = other.mSTokenApp;
- mShare = other.mShare;
- mEAPMethod = other.mEAPMethod;
- mCertType = other.mCertType;
- mFingerPrint = other.mFingerPrint;
- mImsi = other.mImsi;
- }
-
- public static CertType mapCertType(String certType) throws OMAException {
- if (certType.equalsIgnoreCase(CertTypeX509)) {
- return CertType.x509v3;
- } else if (certType.equalsIgnoreCase(CertTypeIEEE)) {
- return CertType.IEEE;
- } else {
- throw new OMAException("Invalid cert type: '" + certType + "'");
- }
- }
-
- public EAPMethod getEAPMethod() {
- return mEAPMethod;
- }
-
- public String getRealm() {
- return mRealm;
- }
-
- public IMSIParameter getImsi() {
- return mImsi;
- }
-
- public String getUserName() {
- return mUserName;
- }
-
- public String getPassword() {
- return mPassword;
- }
-
- public boolean hasDisregardPassword() {
- return mDisregardPassword;
- }
-
- public CertType getCertType() {
- return mCertType;
- }
-
- public byte[] getFingerPrint() {
- return mFingerPrint;
- }
-
- public long getCtime() {
- return mCtime;
- }
-
- public long getExpTime() {
- return mExpTime;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- Credential that = (Credential) o;
-
- if (mCheckAAACert != that.mCheckAAACert) return false;
- if (mCtime != that.mCtime) return false;
- if (mExpTime != that.mExpTime) return false;
- if (mMachineManaged != that.mMachineManaged) return false;
- if (mShare != that.mShare) return false;
- if (mCertType != that.mCertType) return false;
- if (!mEAPMethod.equals(that.mEAPMethod)) return false;
- if (!Arrays.equals(mFingerPrint, that.mFingerPrint)) return false;
- if (!safeEquals(mImsi, that.mImsi)) {
- return false;
- }
-
- if (!mDisregardPassword && !safeEquals(mPassword, that.mPassword)) {
- return false;
- }
-
- if (!mRealm.equals(that.mRealm)) return false;
- if (!safeEquals(mSTokenApp, that.mSTokenApp)) {
- return false;
- }
- if (!safeEquals(mUserName, that.mUserName)) {
- return false;
- }
-
- return true;
- }
-
- private static boolean safeEquals(Object s1, Object s2) {
- if (s1 == null) {
- return s2 == null;
- } else {
- return s2 != null && s1.equals(s2);
- }
- }
-
- @Override
- public int hashCode() {
- int result = (int) (mCtime ^ (mCtime >>> 32));
- result = 31 * result + (int) (mExpTime ^ (mExpTime >>> 32));
- result = 31 * result + mRealm.hashCode();
- result = 31 * result + (mCheckAAACert ? 1 : 0);
- result = 31 * result + (mUserName != null ? mUserName.hashCode() : 0);
- result = 31 * result + (mPassword != null ? mPassword.hashCode() : 0);
- result = 31 * result + (mMachineManaged ? 1 : 0);
- result = 31 * result + (mSTokenApp != null ? mSTokenApp.hashCode() : 0);
- result = 31 * result + (mShare ? 1 : 0);
- result = 31 * result + mEAPMethod.hashCode();
- result = 31 * result + (mCertType != null ? mCertType.hashCode() : 0);
- result = 31 * result + (mFingerPrint != null ? Arrays.hashCode(mFingerPrint) : 0);
- result = 31 * result + (mImsi != null ? mImsi.hashCode() : 0);
- return result;
- }
-
- @Override
- public String toString() {
- return "Credential{" +
- "mCtime=" + Utils.toUTCString(mCtime) +
- ", mExpTime=" + Utils.toUTCString(mExpTime) +
- ", mRealm='" + mRealm + '\'' +
- ", mCheckAAACert=" + mCheckAAACert +
- ", mUserName='" + mUserName + '\'' +
- ", mPassword='" + mPassword + '\'' +
- ", mDisregardPassword=" + mDisregardPassword +
- ", mMachineManaged=" + mMachineManaged +
- ", mSTokenApp='" + mSTokenApp + '\'' +
- ", mShare=" + mShare +
- ", mEAPMethod=" + mEAPMethod +
- ", mCertType=" + mCertType +
- ", mFingerPrint=" + Utils.toHexString(mFingerPrint) +
- ", mImsi='" + mImsi + '\'' +
- '}';
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/pps/DomainMatcher.java b/packages/Osu/src/com/android/hotspot2/pps/DomainMatcher.java
deleted file mode 100644
index 10768d677aa8..000000000000
--- a/packages/Osu/src/com/android/hotspot2/pps/DomainMatcher.java
+++ /dev/null
@@ -1,149 +0,0 @@
-package com.android.hotspot2.pps;
-
-import com.android.hotspot2.Utils;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-public class DomainMatcher {
-
- public enum Match {None, Primary, Secondary}
-
- private final Label mRoot;
-
- private static class Label {
- private final Map<String, Label> mSubDomains;
- private final Match mMatch;
-
- private Label(Match match) {
- mMatch = match;
- mSubDomains = match == Match.None ? new HashMap<String, Label>() : null;
- }
-
- private void addDomain(Iterator<String> labels, Match match) {
- String labelName = labels.next();
- if (labels.hasNext()) {
- Label subLabel = new Label(Match.None);
- mSubDomains.put(labelName, subLabel);
- subLabel.addDomain(labels, match);
- } else {
- mSubDomains.put(labelName, new Label(match));
- }
- }
-
- private Label getSubLabel(String labelString) {
- return mSubDomains.get(labelString);
- }
-
- public Match getMatch() {
- return mMatch;
- }
-
- private void toString(StringBuilder sb) {
- if (mSubDomains != null) {
- sb.append(".{");
- for (Map.Entry<String, Label> entry : mSubDomains.entrySet()) {
- sb.append(entry.getKey());
- entry.getValue().toString(sb);
- }
- sb.append('}');
- } else {
- sb.append('=').append(mMatch);
- }
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- toString(sb);
- return sb.toString();
- }
- }
-
- public DomainMatcher(List<String> primary, List<List<String>> secondary) {
- mRoot = new Label(Match.None);
- for (List<String> secondaryLabel : secondary) {
- mRoot.addDomain(secondaryLabel.iterator(), Match.Secondary);
- }
- // Primary overwrites secondary.
- mRoot.addDomain(primary.iterator(), Match.Primary);
- }
-
- /**
- * Check if domain is either a the same or a sub-domain of any of the domains in the domain tree
- * in this matcher, i.e. all or or a sub-set of the labels in domain matches a path in the tree.
- *
- * @param domain Domain to be checked.
- * @return None if domain is not a sub-domain, Primary if it matched one of the primary domains
- * or Secondary if it matched on of the secondary domains.
- */
- public Match isSubDomain(List<String> domain) {
-
- Label label = mRoot;
- for (String labelString : domain) {
- label = label.getSubLabel(labelString);
- if (label == null) {
- return Match.None;
- } else if (label.getMatch() != Match.None) {
- return label.getMatch();
- }
- }
- return Match.None; // Domain is a super domain
- }
-
- public static boolean arg2SubdomainOfArg1(List<String> arg1, List<String> arg2) {
- if (arg2.size() < arg1.size()) {
- return false;
- }
-
- Iterator<String> l1 = arg1.iterator();
- Iterator<String> l2 = arg2.iterator();
-
- while (l1.hasNext()) {
- if (!l1.next().equals(l2.next())) {
- return false;
- }
- }
- return true;
- }
-
- @Override
- public String toString() {
- return "Domain matcher " + mRoot;
- }
-
- private static final String[] TestDomains = {
- "garbage.apple.com",
- "apple.com",
- "com",
- "jan.android.google.com.",
- "jan.android.google.com",
- "android.google.com",
- "google.com",
- "jan.android.google.net.",
- "jan.android.google.net",
- "android.google.net",
- "google.net",
- "net.",
- "."
- };
-
- public static void main(String[] args) {
- DomainMatcher dm1 = new DomainMatcher(Utils.splitDomain("android.google.com"),
- Collections.<List<String>>emptyList());
- for (String domain : TestDomains) {
- System.out.println(domain + ": " + dm1.isSubDomain(Utils.splitDomain(domain)));
- }
- List<List<String>> secondaries = new ArrayList<List<String>>();
- secondaries.add(Utils.splitDomain("apple.com"));
- secondaries.add(Utils.splitDomain("net"));
- DomainMatcher dm2 = new DomainMatcher(Utils.splitDomain("android.google.com"), secondaries);
- for (String domain : TestDomains) {
- System.out.println(domain + ": " + dm2.isSubDomain(Utils.splitDomain(domain)));
- }
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/pps/HomeSP.java b/packages/Osu/src/com/android/hotspot2/pps/HomeSP.java
deleted file mode 100644
index cfbf9d199daf..000000000000
--- a/packages/Osu/src/com/android/hotspot2/pps/HomeSP.java
+++ /dev/null
@@ -1,211 +0,0 @@
-package com.android.hotspot2.pps;
-
-import com.android.hotspot2.Utils;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-public class HomeSP {
- private final Map<String, Long> mSSIDs; // SSID, HESSID, [0,N]
- private final String mFQDN;
- private final DomainMatcher mDomainMatcher;
- private final Set<String> mOtherHomePartners;
- private final HashSet<Long> mRoamingConsortiums; // [0,N]
- private final Set<Long> mMatchAnyOIs; // [0,N]
- private final List<Long> mMatchAllOIs; // [0,N]
-
- private final Credential mCredential;
-
- // Informational:
- private final String mFriendlyName; // [1]
- private final String mIconURL; // [0,1]
-
- private final Policy mPolicy;
- private final int mCredentialPriority;
- private final Map<String, String> mAAATrustRoots;
- private final UpdateInfo mSubscriptionUpdate;
- private final SubscriptionParameters mSubscriptionParameters;
- private final int mUpdateIdentifier;
-
- @Deprecated
- public HomeSP(Map<String, Long> ssidMap,
- /*@NotNull*/ String fqdn,
- /*@NotNull*/ HashSet<Long> roamingConsortiums,
- /*@NotNull*/ Set<String> otherHomePartners,
- /*@NotNull*/ Set<Long> matchAnyOIs,
- /*@NotNull*/ List<Long> matchAllOIs,
- String friendlyName,
- String iconURL,
- Credential credential) {
-
- mSSIDs = ssidMap;
- List<List<String>> otherPartners = new ArrayList<>(otherHomePartners.size());
- for (String otherPartner : otherHomePartners) {
- otherPartners.add(Utils.splitDomain(otherPartner));
- }
- mOtherHomePartners = otherHomePartners;
- mFQDN = fqdn;
- mDomainMatcher = new DomainMatcher(Utils.splitDomain(fqdn), otherPartners);
- mRoamingConsortiums = roamingConsortiums;
- mMatchAnyOIs = matchAnyOIs;
- mMatchAllOIs = matchAllOIs;
- mFriendlyName = friendlyName;
- mIconURL = iconURL;
- mCredential = credential;
-
- mPolicy = null;
- mCredentialPriority = -1;
- mAAATrustRoots = null;
- mSubscriptionUpdate = null;
- mSubscriptionParameters = null;
- mUpdateIdentifier = -1;
- }
-
- public HomeSP(Map<String, Long> ssidMap,
- /*@NotNull*/ String fqdn,
- /*@NotNull*/ HashSet<Long> roamingConsortiums,
- /*@NotNull*/ Set<String> otherHomePartners,
- /*@NotNull*/ Set<Long> matchAnyOIs,
- /*@NotNull*/ List<Long> matchAllOIs,
- String friendlyName,
- String iconURL,
- Credential credential,
-
- Policy policy,
- int credentialPriority,
- Map<String, String> AAATrustRoots,
- UpdateInfo subscriptionUpdate,
- SubscriptionParameters subscriptionParameters,
- int updateIdentifier) {
-
- mSSIDs = ssidMap;
- List<List<String>> otherPartners = new ArrayList<>(otherHomePartners.size());
- for (String otherPartner : otherHomePartners) {
- otherPartners.add(Utils.splitDomain(otherPartner));
- }
- mOtherHomePartners = otherHomePartners;
- mFQDN = fqdn;
- mDomainMatcher = new DomainMatcher(Utils.splitDomain(fqdn), otherPartners);
- mRoamingConsortiums = roamingConsortiums;
- mMatchAnyOIs = matchAnyOIs;
- mMatchAllOIs = matchAllOIs;
- mFriendlyName = friendlyName;
- mIconURL = iconURL;
- mCredential = credential;
-
- mPolicy = policy;
- mCredentialPriority = credentialPriority;
- mAAATrustRoots = AAATrustRoots;
- mSubscriptionUpdate = subscriptionUpdate;
- mSubscriptionParameters = subscriptionParameters;
- mUpdateIdentifier = updateIdentifier;
- }
-
- public int getUpdateIdentifier() {
- return mUpdateIdentifier;
- }
-
- public UpdateInfo getSubscriptionUpdate() {
- return mSubscriptionUpdate;
- }
-
- public Policy getPolicy() {
- return mPolicy;
- }
-
- private String imsiMatch(List<String> imsis, String mccMnc) {
- if (mCredential.getImsi().matchesMccMnc(mccMnc)) {
- for (String imsi : imsis) {
- if (imsi.startsWith(mccMnc)) {
- return imsi;
- }
- }
- }
- return null;
- }
-
- public String getFQDN() {
- return mFQDN;
- }
-
- public String getFriendlyName() {
- return mFriendlyName;
- }
-
- public HashSet<Long> getRoamingConsortiums() {
- return mRoamingConsortiums;
- }
-
- public Credential getCredential() {
- return mCredential;
- }
-
- public Map<String, Long> getSSIDs() {
- return mSSIDs;
- }
-
- public Collection<String> getOtherHomePartners() {
- return mOtherHomePartners;
- }
-
- public Set<Long> getMatchAnyOIs() {
- return mMatchAnyOIs;
- }
-
- public List<Long> getMatchAllOIs() {
- return mMatchAllOIs;
- }
-
- public String getIconURL() {
- return mIconURL;
- }
-
- public boolean deepEquals(HomeSP other) {
- return mFQDN.equals(other.mFQDN) &&
- mSSIDs.equals(other.mSSIDs) &&
- mOtherHomePartners.equals(other.mOtherHomePartners) &&
- mRoamingConsortiums.equals(other.mRoamingConsortiums) &&
- mMatchAnyOIs.equals(other.mMatchAnyOIs) &&
- mMatchAllOIs.equals(other.mMatchAllOIs) &&
- mFriendlyName.equals(other.mFriendlyName) &&
- Utils.compare(mIconURL, other.mIconURL) == 0 &&
- mCredential.equals(other.mCredential);
- }
-
- @Override
- public boolean equals(Object thatObject) {
- if (this == thatObject) {
- return true;
- } else if (thatObject == null || getClass() != thatObject.getClass()) {
- return false;
- }
-
- HomeSP that = (HomeSP) thatObject;
- return mFQDN.equals(that.mFQDN);
- }
-
- @Override
- public int hashCode() {
- return mFQDN.hashCode();
- }
-
- @Override
- public String toString() {
- return "HomeSP{" +
- "SSIDs=" + mSSIDs +
- ", FQDN='" + mFQDN + '\'' +
- ", DomainMatcher=" + mDomainMatcher +
- ", RoamingConsortiums={" + Utils.roamingConsortiumsToString(mRoamingConsortiums) +
- '}' +
- ", MatchAnyOIs={" + Utils.roamingConsortiumsToString(mMatchAnyOIs) + '}' +
- ", MatchAllOIs={" + Utils.roamingConsortiumsToString(mMatchAllOIs) + '}' +
- ", Credential=" + mCredential +
- ", FriendlyName='" + mFriendlyName + '\'' +
- ", IconURL='" + mIconURL + '\'' +
- '}';
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/pps/Policy.java b/packages/Osu/src/com/android/hotspot2/pps/Policy.java
deleted file mode 100644
index 518043676ba2..000000000000
--- a/packages/Osu/src/com/android/hotspot2/pps/Policy.java
+++ /dev/null
@@ -1,195 +0,0 @@
-package com.android.hotspot2.pps;
-
-import com.android.hotspot2.Utils;
-import com.android.hotspot2.omadm.MOManager;
-import com.android.hotspot2.omadm.OMAException;
-import com.android.hotspot2.omadm.OMANode;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static com.android.hotspot2.omadm.MOManager.TAG_Country;
-import static com.android.hotspot2.omadm.MOManager.TAG_DLBandwidth;
-import static com.android.hotspot2.omadm.MOManager.TAG_FQDN_Match;
-import static com.android.hotspot2.omadm.MOManager.TAG_IPProtocol;
-import static com.android.hotspot2.omadm.MOManager.TAG_MaximumBSSLoadValue;
-import static com.android.hotspot2.omadm.MOManager.TAG_MinBackhaulThreshold;
-import static com.android.hotspot2.omadm.MOManager.TAG_NetworkType;
-import static com.android.hotspot2.omadm.MOManager.TAG_PolicyUpdate;
-import static com.android.hotspot2.omadm.MOManager.TAG_PortNumber;
-import static com.android.hotspot2.omadm.MOManager.TAG_PreferredRoamingPartnerList;
-import static com.android.hotspot2.omadm.MOManager.TAG_Priority;
-import static com.android.hotspot2.omadm.MOManager.TAG_RequiredProtoPortTuple;
-import static com.android.hotspot2.omadm.MOManager.TAG_SPExclusionList;
-import static com.android.hotspot2.omadm.MOManager.TAG_SSID;
-import static com.android.hotspot2.omadm.MOManager.TAG_ULBandwidth;
-
-public class Policy {
- private final List<PreferredRoamingPartner> mPreferredRoamingPartners;
- private final List<MinBackhaul> mMinBackhaulThresholds;
- private final UpdateInfo mPolicyUpdate;
- private final List<String> mSPExclusionList;
- private final Map<Integer, List<Integer>> mRequiredProtos;
- private final int mMaxBSSLoad;
-
- public Policy(OMANode node) throws OMAException {
-
- OMANode rpNode = node.getChild(TAG_PreferredRoamingPartnerList);
- if (rpNode == null) {
- mPreferredRoamingPartners = null;
- } else {
- mPreferredRoamingPartners = new ArrayList<>(rpNode.getChildren().size());
- for (OMANode instance : rpNode.getChildren()) {
- if (instance.isLeaf()) {
- throw new OMAException("Not expecting leaf node in " +
- TAG_PreferredRoamingPartnerList);
- }
- mPreferredRoamingPartners.add(new PreferredRoamingPartner(instance));
- }
- }
-
- OMANode bhtNode = node.getChild(TAG_MinBackhaulThreshold);
- if (bhtNode == null) {
- mMinBackhaulThresholds = null;
- } else {
- mMinBackhaulThresholds = new ArrayList<>(bhtNode.getChildren().size());
- for (OMANode instance : bhtNode.getChildren()) {
- if (instance.isLeaf()) {
- throw new OMAException("Not expecting leaf node in " +
- TAG_MinBackhaulThreshold);
- }
- mMinBackhaulThresholds.add(new MinBackhaul(instance));
- }
- }
-
- mPolicyUpdate = new UpdateInfo(node.getChild(TAG_PolicyUpdate));
-
- OMANode sxNode = node.getChild(TAG_SPExclusionList);
- if (sxNode == null) {
- mSPExclusionList = null;
- } else {
- mSPExclusionList = new ArrayList<>(sxNode.getChildren().size());
- for (OMANode instance : sxNode.getChildren()) {
- if (instance.isLeaf()) {
- throw new OMAException("Not expecting leaf node in " + TAG_SPExclusionList);
- }
- mSPExclusionList.add(MOManager.getString(instance, TAG_SSID));
- }
- }
-
- OMANode rptNode = node.getChild(TAG_RequiredProtoPortTuple);
- if (rptNode == null) {
- mRequiredProtos = null;
- } else {
- mRequiredProtos = new HashMap<>(rptNode.getChildren().size());
- for (OMANode instance : rptNode.getChildren()) {
- if (instance.isLeaf()) {
- throw new OMAException("Not expecting leaf node in " +
- TAG_RequiredProtoPortTuple);
- }
- int protocol = (int) MOManager.getLong(instance, TAG_IPProtocol, null);
- String[] portSegments = MOManager.getString(instance, TAG_PortNumber).split(",");
- List<Integer> ports = new ArrayList<>(portSegments.length);
- for (String portSegment : portSegments) {
- try {
- ports.add(Integer.parseInt(portSegment));
- } catch (NumberFormatException nfe) {
- throw new OMAException("Port is not a number: " + portSegment);
- }
- }
- mRequiredProtos.put(protocol, ports);
- }
- }
-
- mMaxBSSLoad = (int) MOManager.getLong(node, TAG_MaximumBSSLoadValue, Long.MAX_VALUE);
- }
-
- public List<PreferredRoamingPartner> getPreferredRoamingPartners() {
- return mPreferredRoamingPartners;
- }
-
- public List<MinBackhaul> getMinBackhaulThresholds() {
- return mMinBackhaulThresholds;
- }
-
- public UpdateInfo getPolicyUpdate() {
- return mPolicyUpdate;
- }
-
- public List<String> getSPExclusionList() {
- return mSPExclusionList;
- }
-
- public Map<Integer, List<Integer>> getRequiredProtos() {
- return mRequiredProtos;
- }
-
- public int getMaxBSSLoad() {
- return mMaxBSSLoad;
- }
-
- private static class PreferredRoamingPartner {
- private final List<String> mDomain;
- private final Boolean mIncludeSubDomains;
- private final int mPriority;
- private final String mCountry;
-
- private PreferredRoamingPartner(OMANode node)
- throws OMAException {
-
- String[] segments = MOManager.getString(node, TAG_FQDN_Match).split(",");
- if (segments.length != 2) {
- throw new OMAException("Bad FQDN match string: " + TAG_FQDN_Match);
- }
- mDomain = Utils.splitDomain(segments[0]);
- mIncludeSubDomains = MOManager.getSelection(TAG_FQDN_Match, segments[1]);
- mPriority = (int) MOManager.getLong(node, TAG_Priority, null);
- mCountry = MOManager.getString(node, TAG_Country);
- }
-
- @Override
- public String toString() {
- return "PreferredRoamingPartner{" +
- "domain=" + mDomain +
- ", includeSubDomains=" + mIncludeSubDomains +
- ", priority=" + mPriority +
- ", country='" + mCountry + '\'' +
- '}';
- }
- }
-
- private static class MinBackhaul {
- private final Boolean mHome;
- private final long mDL;
- private final long mUL;
-
- private MinBackhaul(OMANode node) throws OMAException {
- mHome = MOManager.getSelection(node, TAG_NetworkType);
- mDL = MOManager.getLong(node, TAG_DLBandwidth, Long.MAX_VALUE);
- mUL = MOManager.getLong(node, TAG_ULBandwidth, Long.MAX_VALUE);
- }
-
- @Override
- public String toString() {
- return "MinBackhaul{" +
- "home=" + mHome +
- ", DL=" + mDL +
- ", UL=" + mUL +
- '}';
- }
- }
-
- @Override
- public String toString() {
- return "Policy{" +
- "preferredRoamingPartners=" + mPreferredRoamingPartners +
- ", minBackhaulThresholds=" + mMinBackhaulThresholds +
- ", policyUpdate=" + mPolicyUpdate +
- ", SPExclusionList=" + mSPExclusionList +
- ", requiredProtos=" + mRequiredProtos +
- ", maxBSSLoad=" + mMaxBSSLoad +
- '}';
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/pps/SubscriptionParameters.java b/packages/Osu/src/com/android/hotspot2/pps/SubscriptionParameters.java
deleted file mode 100644
index e073ad786666..000000000000
--- a/packages/Osu/src/com/android/hotspot2/pps/SubscriptionParameters.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.android.hotspot2.pps;
-
-import com.android.hotspot2.Utils;
-import com.android.hotspot2.omadm.MOManager;
-import com.android.hotspot2.omadm.OMAException;
-import com.android.hotspot2.omadm.OMANode;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static com.android.hotspot2.omadm.MOManager.TAG_CreationDate;
-import static com.android.hotspot2.omadm.MOManager.TAG_DataLimit;
-import static com.android.hotspot2.omadm.MOManager.TAG_ExpirationDate;
-import static com.android.hotspot2.omadm.MOManager.TAG_StartDate;
-import static com.android.hotspot2.omadm.MOManager.TAG_TimeLimit;
-import static com.android.hotspot2.omadm.MOManager.TAG_TypeOfSubscription;
-import static com.android.hotspot2.omadm.MOManager.TAG_UsageLimits;
-import static com.android.hotspot2.omadm.MOManager.TAG_UsageTimePeriod;
-
-public class SubscriptionParameters {
- private final long mCDate;
- private final long mXDate;
- private final String mType;
- private final List<Limit> mLimits;
-
- public SubscriptionParameters(OMANode node) throws OMAException {
- mCDate = MOManager.getTime(node.getChild(TAG_CreationDate));
- mXDate = MOManager.getTime(node.getChild(TAG_ExpirationDate));
- mType = MOManager.getString(node.getChild(TAG_TypeOfSubscription));
-
- OMANode ulNode = node.getChild(TAG_UsageLimits);
- if (ulNode == null) {
- mLimits = null;
- } else {
- mLimits = new ArrayList<>(ulNode.getChildren().size());
- for (OMANode instance : ulNode.getChildren()) {
- if (instance.isLeaf()) {
- throw new OMAException("Not expecting leaf node in " +
- TAG_UsageLimits);
- }
- mLimits.add(new Limit(instance));
- }
- }
-
- }
-
- private static class Limit {
- private final long mDataLimit;
- private final long mStartDate;
- private final long mTimeLimit;
- private final long mUsageTimePeriod;
-
- private Limit(OMANode node) throws OMAException {
- mDataLimit = MOManager.getLong(node, TAG_DataLimit, Long.MAX_VALUE);
- mStartDate = MOManager.getTime(node.getChild(TAG_StartDate));
- mTimeLimit = MOManager.getLong(node, TAG_TimeLimit, Long.MAX_VALUE) *
- MOManager.IntervalFactor;
- mUsageTimePeriod = MOManager.getLong(node, TAG_UsageTimePeriod, null);
- }
-
- @Override
- public String toString() {
- return "Limit{" +
- "dataLimit=" + mDataLimit +
- ", startDate=" + Utils.toUTCString(mStartDate) +
- ", timeLimit=" + mTimeLimit +
- ", usageTimePeriod=" + mUsageTimePeriod +
- '}';
- }
- }
-
- @Override
- public String toString() {
- return "SubscriptionParameters{" +
- "cDate=" + Utils.toUTCString(mCDate) +
- ", xDate=" + Utils.toUTCString(mXDate) +
- ", type='" + mType + '\'' +
- ", limits=" + mLimits +
- '}';
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/pps/UpdateInfo.java b/packages/Osu/src/com/android/hotspot2/pps/UpdateInfo.java
deleted file mode 100644
index 645e1fa485a3..000000000000
--- a/packages/Osu/src/com/android/hotspot2/pps/UpdateInfo.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package com.android.hotspot2.pps;
-
-import android.util.Base64;
-
-import com.android.hotspot2.Utils;
-import com.android.hotspot2.omadm.MOManager;
-import com.android.hotspot2.omadm.OMAException;
-import com.android.hotspot2.omadm.OMANode;
-
-import java.nio.charset.StandardCharsets;
-
-import static com.android.hotspot2.omadm.MOManager.TAG_CertSHA256Fingerprint;
-import static com.android.hotspot2.omadm.MOManager.TAG_CertURL;
-import static com.android.hotspot2.omadm.MOManager.TAG_Password;
-import static com.android.hotspot2.omadm.MOManager.TAG_Restriction;
-import static com.android.hotspot2.omadm.MOManager.TAG_TrustRoot;
-import static com.android.hotspot2.omadm.MOManager.TAG_URI;
-import static com.android.hotspot2.omadm.MOManager.TAG_UpdateInterval;
-import static com.android.hotspot2.omadm.MOManager.TAG_UpdateMethod;
-import static com.android.hotspot2.omadm.MOManager.TAG_Username;
-import static com.android.hotspot2.omadm.MOManager.TAG_UsernamePassword;
-
-public class UpdateInfo {
- public enum UpdateRestriction {HomeSP, RoamingPartner, Unrestricted}
-
- public static final long NO_UPDATE = 0xffffffffL;
-
- private final long mInterval;
- private final boolean mSPPClientInitiated;
- private final UpdateRestriction mUpdateRestriction;
- private final String mURI;
- private final String mUsername;
- private final String mPassword;
- private final String mCertURL;
- private final String mCertFP;
-
- public UpdateInfo(OMANode policyUpdate) throws OMAException {
- long minutes = MOManager.getLong(policyUpdate, TAG_UpdateInterval, null);
- mInterval = minutes == NO_UPDATE ? -1 : minutes * MOManager.IntervalFactor;
- mSPPClientInitiated = MOManager.getSelection(policyUpdate, TAG_UpdateMethod);
- mUpdateRestriction = MOManager.getSelection(policyUpdate, TAG_Restriction);
- mURI = MOManager.getString(policyUpdate, TAG_URI);
-
- OMANode unp = policyUpdate.getChild(TAG_UsernamePassword);
- if (unp != null) {
- mUsername = MOManager.getString(unp.getChild(TAG_Username));
- String pw = MOManager.getString(unp.getChild(TAG_Password));
- mPassword = new String(Base64.decode(pw.getBytes(StandardCharsets.US_ASCII),
- Base64.DEFAULT), StandardCharsets.UTF_8);
- } else {
- mUsername = null;
- mPassword = null;
- }
-
- OMANode trustRoot = MOManager.getChild(policyUpdate, TAG_TrustRoot);
- mCertURL = MOManager.getString(trustRoot, TAG_CertURL);
- mCertFP = MOManager.getString(trustRoot, TAG_CertSHA256Fingerprint);
- }
-
- public long getInterval() {
- return mInterval;
- }
-
- public boolean isSPPClientInitiated() {
- return mSPPClientInitiated;
- }
-
- public UpdateRestriction getUpdateRestriction() {
- return mUpdateRestriction;
- }
-
- public String getURI() {
- return mURI;
- }
-
- public String getUsername() {
- return mUsername;
- }
-
- public String getPassword() {
- return mPassword;
- }
-
- public String getCertURL() {
- return mCertURL;
- }
-
- public String getCertFP() {
- return mCertFP;
- }
-
- @Override
- public String toString() {
- return "UpdateInfo{" +
- "interval=" + Utils.toHMS(mInterval) +
- ", SPPClientInitiated=" + mSPPClientInitiated +
- ", updateRestriction=" + mUpdateRestriction +
- ", URI='" + mURI + '\'' +
- ", username='" + mUsername + '\'' +
- ", password=" + mPassword +
- ", certURL='" + mCertURL + '\'' +
- ", certFP='" + mCertFP + '\'' +
- '}';
- }
-}
diff --git a/packages/Osu/src/com/android/hotspot2/utils/HTTPMessage.java b/packages/Osu/src/com/android/hotspot2/utils/HTTPMessage.java
deleted file mode 100644
index c675efd2295c..000000000000
--- a/packages/Osu/src/com/android/hotspot2/utils/HTTPMessage.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.android.hotspot2.utils;
-
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.util.Map;
-
-public interface HTTPMessage {
- public static final String HTTPVersion = "HTTP/1.1";
- public static final String AgentHeader = "User-Agent";
- public static final String AgentName = "Android HS Client";
- public static final String HostHeader = "Host";
- public static final String AcceptHeader = "Accept";
- public static final String LengthHeader = "Content-Length";
- public static final String ContentTypeHeader = "Content-Type";
- public static final String ContentLengthHeader = "Content-Length";
- public static final String ContentEncodingHeader = "Content-Transfer-Encoding";
- public static final String AuthHeader = "WWW-Authenticate";
- public static final String AuthorizationHeader = "Authorization";
-
- public static final String ContentTypeSOAP = "application/soap+xml";
-
- public static final int RX_BUFFER = 32768;
- public static final String CRLF = "\r\n";
- public static final int BODY_SEPARATOR = 0x0d0a0d0a;
- public static final int BODY_SEPARATOR_LENGTH = 4;
-
- public enum Method {GET, PUT, POST}
-
- public Map<String, String> getHeaders();
-
- public InputStream getPayloadStream();
-
- public ByteBuffer getPayload();
-
- public ByteBuffer getBinaryPayload();
-}
diff --git a/packages/Osu/src/com/android/hotspot2/utils/HTTPRequest.java b/packages/Osu/src/com/android/hotspot2/utils/HTTPRequest.java
deleted file mode 100644
index e97c15a0fa23..000000000000
--- a/packages/Osu/src/com/android/hotspot2/utils/HTTPRequest.java
+++ /dev/null
@@ -1,307 +0,0 @@
-package com.android.hotspot2.utils;
-
-import android.util.Base64;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URL;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.security.GeneralSecurityException;
-import java.security.MessageDigest;
-import java.security.SecureRandom;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
-
-public class HTTPRequest implements HTTPMessage {
- private static final Charset HeaderCharset = StandardCharsets.US_ASCII;
- private static final int HTTPS_PORT = 443;
-
- private final String mMethodLine;
- private final Map<String, String> mHeaderFields;
- private final byte[] mBody;
-
- public HTTPRequest(Method method, URL url) {
- this(null, null, method, url, null, false);
- }
-
- public HTTPRequest(String payload, Charset charset, Method method, URL url, String contentType,
- boolean base64) {
- mBody = payload != null ? payload.getBytes(charset) : null;
-
- mHeaderFields = new LinkedHashMap<>();
- mHeaderFields.put(AgentHeader, AgentName);
- if (url.getPort() != HTTPS_PORT) {
- mHeaderFields.put(HostHeader, url.getHost() + ':' + url.getPort());
- } else {
- mHeaderFields.put(HostHeader, url.getHost());
- }
- mHeaderFields.put(AcceptHeader, "*/*");
- if (payload != null) {
- if (base64) {
- mHeaderFields.put(ContentTypeHeader, contentType);
- mHeaderFields.put(ContentEncodingHeader, "base64");
- } else {
- mHeaderFields.put(ContentTypeHeader, contentType + "; charset=" +
- charset.displayName().toLowerCase());
- }
- mHeaderFields.put(ContentLengthHeader, Integer.toString(mBody.length));
- }
-
- mMethodLine = method.name() + ' ' + url.getPath() + ' ' + HTTPVersion + CRLF;
- }
-
- public void doAuthenticate(HTTPResponse httpResponse, String userName, byte[] password,
- URL url, int sequence) throws IOException, GeneralSecurityException {
- mHeaderFields.put(HTTPMessage.AuthorizationHeader,
- generateAuthAnswer(httpResponse, userName, password, url, sequence));
- }
-
- private static String generateAuthAnswer(HTTPResponse httpResponse, String userName,
- byte[] password, URL url, int sequence)
- throws IOException, GeneralSecurityException {
-
- String authRequestLine = httpResponse.getHeader(HTTPMessage.AuthHeader);
- if (authRequestLine == null) {
- throw new IOException("Missing auth line");
- }
- String[] tokens = authRequestLine.split("[ ,]+");
- //System.out.println("Tokens: " + Arrays.toString(tokens));
- if (tokens.length < 3 || !tokens[0].equalsIgnoreCase("digest")) {
- throw new IOException("Bad " + HTTPMessage.AuthHeader + ": '" + authRequestLine + "'");
- }
-
- Map<String, String> itemMap = new HashMap<>();
- for (int n = 1; n < tokens.length; n++) {
- String s = tokens[n];
- int split = s.indexOf('=');
- if (split < 0) {
- continue;
- }
- itemMap.put(s.substring(0, split).trim().toLowerCase(),
- unquote(s.substring(split + 1).trim()));
- }
-
- Set<String> qops = splitValue(itemMap.remove("qop"));
- if (!qops.contains("auth")) {
- throw new IOException("Unsupported quality of protection value(s): '" + qops + "'");
- }
- String algorithm = itemMap.remove("algorithm");
- if (algorithm != null && !algorithm.equalsIgnoreCase("md5")) {
- throw new IOException("Unsupported algorithm: '" + algorithm + "'");
- }
- String realm = itemMap.remove("realm");
- String nonceText = itemMap.remove("nonce");
- if (realm == null || nonceText == null) {
- throw new IOException("realm and/or nonce missing: '" + authRequestLine + "'");
- }
- //System.out.println("Remaining tokens: " + itemMap);
-
- byte[] cnonce = new byte[16];
- SecureRandom prng = new SecureRandom();
- prng.nextBytes(cnonce);
-
- /*
- * H(data) = MD5(data)
- * KD(secret, data) = H(concat(secret, ":", data))
- *
- * A1 = unq(username-value) ":" unq(realm-value) ":" passwd
- * A2 = Method ":" digest-uri-value
- *
- * response = KD ( H(A1), unq(nonce-value) ":" nc-value ":" unq(cnonce-value) ":"
- * unq(qop-value) ":" H(A2) )
- */
-
- String nc = String.format("%08d", sequence);
-
- /*
- * This bears witness to the ingenuity of the emerging "web generation" and the authors of
- * RFC-2617: Strings are treated as a sequence of octets in blind ignorance of character
- * encoding, whereas octets strings apparently aren't "good enough" and expanded to
- * "hex strings"...
- * As a wild guess I apply UTF-8 below.
- */
- String passwordString = new String(password, StandardCharsets.UTF_8);
- String cNonceString = bytesToHex(cnonce);
-
- byte[] a1 = hash(userName, realm, passwordString);
- byte[] a2 = hash("POST", url.getPath());
- byte[] response = hash(a1, nonceText, nc, cNonceString, "auth", a2);
-
- StringBuilder authLine = new StringBuilder();
- authLine.append("Digest ")
- .append("username=\"").append(userName).append("\", ")
- .append("realm=\"").append(realm).append("\", ")
- .append("nonce=\"").append(nonceText).append("\", ")
- .append("uri=\"").append(url.getPath()).append("\", ")
- .append("qop=\"auth\", ")
- .append("nc=").append(nc).append(", ")
- .append("cnonce=\"").append(cNonceString).append("\", ")
- .append("response=\"").append(bytesToHex(response)).append('"');
- String opaque = itemMap.get("opaque");
- if (opaque != null) {
- authLine.append(", \"").append(opaque).append('"');
- }
-
- return authLine.toString();
- }
-
- private static Set<String> splitValue(String value) {
- Set<String> result = new HashSet<>();
- if (value != null) {
- for (String s : value.split(",")) {
- result.add(s.trim());
- }
- }
- return result;
- }
-
- private static byte[] hash(Object... objects) throws GeneralSecurityException {
- MessageDigest hash = MessageDigest.getInstance("MD5");
-
- //System.out.println("<Hash>");
- boolean first = true;
- for (Object object : objects) {
- byte[] octets;
- if (object.getClass() == String.class) {
- //System.out.println("+= '" + object + "'");
- octets = ((String) object).getBytes(StandardCharsets.UTF_8);
- } else {
- octets = bytesToHexBytes((byte[]) object);
- //System.out.println("+= " + new String(octets, StandardCharsets.ISO_8859_1));
- }
- if (first) {
- first = false;
- } else {
- hash.update((byte) ':');
- }
- hash.update(octets);
- }
- //System.out.println("</Hash>");
- return hash.digest();
- }
-
- private static String unquote(String s) {
- return s.startsWith("\"") ? s.substring(1, s.length() - 1) : s;
- }
-
- private static byte[] bytesToHexBytes(byte[] octets) {
- return bytesToHex(octets).getBytes(StandardCharsets.ISO_8859_1);
- }
-
- private static String bytesToHex(byte[] octets) {
- StringBuilder sb = new StringBuilder(octets.length * 2);
- for (byte b : octets) {
- sb.append(String.format("%02x", b & 0xff));
- }
- return sb.toString();
- }
-
- private byte[] buildHeader() {
- StringBuilder header = new StringBuilder();
- header.append(mMethodLine);
- for (Map.Entry<String, String> entry : mHeaderFields.entrySet()) {
- header.append(entry.getKey()).append(": ").append(entry.getValue()).append(CRLF);
- }
- header.append(CRLF);
-
- //System.out.println("HTTP Request:");
- StringBuilder sb2 = new StringBuilder();
- sb2.append(header);
- if (mBody != null) {
- sb2.append(new String(mBody, StandardCharsets.ISO_8859_1));
- }
- //System.out.println(sb2);
- //System.out.println("End HTTP Request.");
-
- return header.toString().getBytes(HeaderCharset);
- }
-
- public void send(OutputStream out) throws IOException {
- out.write(buildHeader());
- if (mBody != null) {
- out.write(mBody);
- }
- out.flush();
- }
-
- @Override
- public Map<String, String> getHeaders() {
- return Collections.unmodifiableMap(mHeaderFields);
- }
-
- @Override
- public InputStream getPayloadStream() {
- return mBody != null ? new ByteArrayInputStream(mBody) : null;
- }
-
- @Override
- public ByteBuffer getPayload() {
- return mBody != null ? ByteBuffer.wrap(mBody) : null;
- }
-
- @Override
- public ByteBuffer getBinaryPayload() {
- byte[] binary = Base64.decode(mBody, Base64.DEFAULT);
- return ByteBuffer.wrap(binary);
- }
-
- public static void main(String[] args) throws GeneralSecurityException {
- test("Mufasa", "testrealm@host.com", "Circle Of Life", "GET", "/dir/index.html",
- "dcd98b7102dd2f0e8b11d0f600bfb0c093", "0a4f113b", "00000001", "auth",
- "6629fae49393a05397450978507c4ef1");
-
- // WWW-Authenticate: Digest realm="wi-fi.org", qop="auth",
- // nonce="MTQzMTg1MTIxMzUyNzo0OGFhNGU5ZTg4Y2M4YmFhYzM2MzAwZDg5MGNiYTJlNw=="
- // Authorization: Digest
- // username="1c7e1582-604d-4c00-b411-bb73735cbcb0"
- // realm="wi-fi.org"
- // nonce="MTQzMTg1MTIxMzUyNzo0OGFhNGU5ZTg4Y2M4YmFhYzM2MzAwZDg5MGNiYTJlNw=="
- // uri="/.well-known/est/simpleenroll"
- // cnonce="NzA3NDk0"
- // nc=00000001
- // qop="auth"
- // response="2c485d24076452e712b77f4e70776463"
-
- String nonce = "MTQzMTg1MTIxMzUyNzo0OGFhNGU5ZTg4Y2M4YmFhYzM2MzAwZDg5MGNiYTJlNw==";
- String cnonce = "NzA3NDk0";
- test("1c7e1582-604d-4c00-b411-bb73735cbcb0", "wi-fi.org", "ruckus1234", "POST",
- "/.well-known/est/simpleenroll",
- /*new String(Base64.getDecoder().decode(nonce), StandardCharsets.ISO_8859_1)*/
- nonce,
- /*new String(Base64.getDecoder().decode(cnonce), StandardCharsets.ISO_8859_1)*/
- cnonce, "00000001", "auth", "2c485d24076452e712b77f4e70776463");
- }
-
- private static void test(String user, String realm, String password, String method, String path,
- String nonce, String cnonce, String nc, String qop, String expect)
- throws GeneralSecurityException {
- byte[] a1 = hash(user, realm, password);
- System.out.println("HA1: " + bytesToHex(a1));
- byte[] a2 = hash(method, path);
- System.out.println("HA2: " + bytesToHex(a2));
- byte[] response = hash(a1, nonce, nc, cnonce, qop, a2);
-
- StringBuilder authLine = new StringBuilder();
- String responseString = bytesToHex(response);
- authLine.append("Digest ")
- .append("username=\"").append(user).append("\", ")
- .append("realm=\"").append(realm).append("\", ")
- .append("nonce=\"").append(nonce).append("\", ")
- .append("uri=\"").append(path).append("\", ")
- .append("qop=\"").append(qop).append("\", ")
- .append("nc=").append(nc).append(", ")
- .append("cnonce=\"").append(cnonce).append("\", ")
- .append("response=\"").append(responseString).append('"');
-
- System.out.println(authLine);
- System.out.println("Success: " + responseString.equals(expect));
- }
-} \ No newline at end of file
diff --git a/packages/Osu/src/com/android/hotspot2/utils/HTTPResponse.java b/packages/Osu/src/com/android/hotspot2/utils/HTTPResponse.java
deleted file mode 100644
index b82814d11fd4..000000000000
--- a/packages/Osu/src/com/android/hotspot2/utils/HTTPResponse.java
+++ /dev/null
@@ -1,181 +0,0 @@
-package com.android.hotspot2.utils;
-
-import android.util.Base64;
-import android.util.Log;
-
-import com.android.hotspot2.osu.OSUManager;
-
-import java.io.ByteArrayInputStream;
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-public class HTTPResponse implements HTTPMessage {
- private final int mStatusCode;
- private final Map<String, String> mHeaders = new LinkedHashMap<>();
- private final ByteBuffer mBody;
-
- private static final String csIndicator = "charset=";
-
- public HTTPResponse(InputStream in) throws IOException {
- int expected = Integer.MAX_VALUE;
- int offset = 0;
- int body = -1;
- byte[] input = new byte[RX_BUFFER];
-
- int statusCode = -1;
- int bodyPattern = 0;
-
- while (offset < expected) {
- int amount = in.read(input, offset, input.length - offset);
- if (amount < 0) {
- throw new EOFException();
- }
-
- if (body < 0) {
- for (int n = offset; n < offset + amount; n++) {
- bodyPattern = (bodyPattern << 8) | (input[n] & 0xff);
- if (bodyPattern == 0x0d0a0d0a) {
- body = n + 1;
- statusCode = parseHeader(input, body, mHeaders);
- expected = calculateLength(body, mHeaders);
- if (expected > input.length) {
- input = Arrays.copyOf(input, expected);
- }
- break;
- }
- }
- }
- offset += amount;
- if (offset < expected && offset == input.length) {
- input = Arrays.copyOf(input, input.length * 2);
- }
- }
- mStatusCode = statusCode;
- mBody = ByteBuffer.wrap(input, body, expected - body);
- }
-
- private static int parseHeader(byte[] input, int body, Map<String, String> headers)
- throws IOException {
- String headerText = new String(input, 0, body - BODY_SEPARATOR_LENGTH,
- StandardCharsets.ISO_8859_1);
- //System.out.println("Received header: " + headerText);
- Iterator<String> headerLines = Arrays.asList(headerText.split(CRLF)).iterator();
- if (!headerLines.hasNext()) {
- throw new IOException("Bad HTTP Request");
- }
-
- int statusCode;
- String line0 = headerLines.next();
- String[] status = line0.split(" ");
- if (status.length != 3 || !"HTTP/1.1".equals(status[0])) {
- throw new IOException("Bad HTTP Result: " + line0);
- }
- try {
- statusCode = Integer.parseInt(status[1].trim());
- } catch (NumberFormatException nfe) {
- throw new IOException("Bad HTTP header line: '" + line0 + "'");
- }
-
- while (headerLines.hasNext()) {
- String line = headerLines.next();
- int keyEnd = line.indexOf(':');
- if (keyEnd < 0) {
- throw new IOException("Bad header line: '" + line + "'");
- }
- String key = line.substring(0, keyEnd).trim();
- String value = line.substring(keyEnd + 1).trim();
- headers.put(key, value);
- }
- return statusCode;
- }
-
- private static int calculateLength(int body, Map<String, String> headers) throws IOException {
- String contentLength = headers.get(LengthHeader);
- if (contentLength == null) {
- throw new IOException("No " + LengthHeader);
- }
- try {
- return body + Integer.parseInt(contentLength);
- } catch (NumberFormatException nfe) {
- throw new IOException("Bad " + LengthHeader + ": " + contentLength);
- }
- }
-
- public int getStatusCode() {
- return mStatusCode;
- }
-
- @Override
- public Map<String, String> getHeaders() {
- return Collections.unmodifiableMap(mHeaders);
- }
-
- public String getHeader(String key) {
- return mHeaders.get(key);
- }
-
- @Override
- public InputStream getPayloadStream() {
- return new ByteArrayInputStream(mBody.array(), mBody.position(),
- mBody.limit() - mBody.position());
- }
-
- @Override
- public ByteBuffer getPayload() {
- return mBody.duplicate();
- }
-
- @Override
- public ByteBuffer getBinaryPayload() {
- byte[] data = new byte[mBody.remaining()];
- mBody.duplicate().get(data);
- byte[] binary = Base64.decode(data, Base64.DEFAULT);
- return ByteBuffer.wrap(binary);
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("Status: ").append(mStatusCode).append(CRLF);
- for (Map.Entry<String, String> entry : mHeaders.entrySet()) {
- sb.append(entry.getKey()).append(": ").append(entry.getValue()).append(CRLF);
- }
- sb.append(CRLF);
- Charset charset;
- try {
- charset = Charset.forName(getCharset());
- } catch (IllegalArgumentException iae) {
- charset = StandardCharsets.ISO_8859_1;
- }
- sb.append(new String(mBody.array(), mBody.position(),
- mBody.limit() - mBody.position(), charset));
- return sb.toString();
- }
-
- public String getCharset() {
- String contentType = mHeaders.get(ContentTypeHeader);
- if (contentType == null) {
- return null;
- }
- int csPos = contentType.indexOf(csIndicator);
- return csPos < 0 ? null : contentType.substring(csPos + csIndicator.length()).trim();
- }
-
- private static boolean equals(byte[] b1, int offset, byte[] pattern) {
- for (int n = 0; n < pattern.length; n++) {
- if (b1[n + offset] != pattern[n]) {
- return false;
- }
- }
- return true;
- }
-}
diff --git a/packages/Osu2/Android.mk b/packages/Osu2/Android.mk
deleted file mode 100644
index 7de89080e919..000000000000
--- a/packages/Osu2/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := Osu2
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_PACKAGE)
-
-########################
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/Osu2/AndroidManifest.xml b/packages/Osu2/AndroidManifest.xml
deleted file mode 100644
index 236b120b950c..000000000000
--- a/packages/Osu2/AndroidManifest.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * 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.
- */
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.osu">
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
- <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
- <uses-permission android:name="android.permission.READ_PHONE_STATE" />
- <uses-permission android:name="android.permission.INTERNET" />
-
- <application
- android:enabled="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name">
- <activity android:name=".MainActivity" android:exported="true">
- </activity>
- </application>
-
-</manifest>
diff --git a/packages/Osu2/res/layout/activity_main.xml b/packages/Osu2/res/layout/activity_main.xml
deleted file mode 100644
index f9504c9a46c8..000000000000
--- a/packages/Osu2/res/layout/activity_main.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
-</LinearLayout>
diff --git a/packages/Osu2/res/mipmap-hdpi/ic_launcher.png b/packages/Osu2/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index cde69bcccec6..000000000000
--- a/packages/Osu2/res/mipmap-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/packages/Osu2/res/mipmap-mdpi/ic_launcher.png b/packages/Osu2/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index c133a0cbd379..000000000000
--- a/packages/Osu2/res/mipmap-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/packages/Osu2/res/mipmap-xhdpi/ic_launcher.png b/packages/Osu2/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index bfa42f0e7b91..000000000000
--- a/packages/Osu2/res/mipmap-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/packages/Osu2/res/mipmap-xxhdpi/ic_launcher.png b/packages/Osu2/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 324e72cdd748..000000000000
--- a/packages/Osu2/res/mipmap-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/packages/Osu2/res/mipmap-xxxhdpi/ic_launcher.png b/packages/Osu2/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index aee44e138434..000000000000
--- a/packages/Osu2/res/mipmap-xxxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/packages/Osu2/res/values-w820dp/dimens.xml b/packages/Osu2/res/values-w820dp/dimens.xml
deleted file mode 100644
index 63fc81644461..000000000000
--- a/packages/Osu2/res/values-w820dp/dimens.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<resources>
- <!-- Example customization of dimensions originally defined in res/values/dimens.xml
- (such as screen margins) for screens with more than 820dp of available width. This
- would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
- <dimen name="activity_horizontal_margin">64dp</dimen>
-</resources>
diff --git a/packages/Osu2/res/values/colors.xml b/packages/Osu2/res/values/colors.xml
deleted file mode 100644
index 3ab3e9cbce07..000000000000
--- a/packages/Osu2/res/values/colors.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <color name="colorPrimary">#3F51B5</color>
- <color name="colorPrimaryDark">#303F9F</color>
- <color name="colorAccent">#FF4081</color>
-</resources>
diff --git a/packages/Osu2/res/values/dimens.xml b/packages/Osu2/res/values/dimens.xml
deleted file mode 100644
index 47c82246738c..000000000000
--- a/packages/Osu2/res/values/dimens.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<resources>
- <!-- Default screen margins, per the Android Design guidelines. -->
- <dimen name="activity_horizontal_margin">16dp</dimen>
- <dimen name="activity_vertical_margin">16dp</dimen>
-</resources>
diff --git a/packages/Osu2/res/values/strings.xml b/packages/Osu2/res/values/strings.xml
deleted file mode 100644
index e5b1af6edd0c..000000000000
--- a/packages/Osu2/res/values/strings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-<resources>
- <string name="app_name">Passpoint Online Sign-Up</string>
-</resources>
diff --git a/packages/Osu2/src/com/android/osu/Constants.java b/packages/Osu2/src/com/android/osu/Constants.java
deleted file mode 100644
index cd046d857b4c..000000000000
--- a/packages/Osu2/src/com/android/osu/Constants.java
+++ /dev/null
@@ -1,24 +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 com.android.osu;
-
-public final class Constants {
- public static final String INTENT_EXTRA_COMMAND = "com.android.osu.extra.COMMAND";
- public static final String INTENT_EXTRA_OSU_PROVIDER = "com.android.osu.extra.OSU_PROVIDER";
-
- public static final String COMMAND_PROVISION = "Provision";
-} \ No newline at end of file
diff --git a/packages/Osu2/src/com/android/osu/MainActivity.java b/packages/Osu2/src/com/android/osu/MainActivity.java
deleted file mode 100644
index 4e2136b99c74..000000000000
--- a/packages/Osu2/src/com/android/osu/MainActivity.java
+++ /dev/null
@@ -1,76 +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 com.android.osu;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.net.wifi.hotspot2.OsuProvider;
-import android.os.Bundle;
-import android.util.Log;
-
-/**
- * Main entry point for the OSU (Online Sign-Up) app.
- */
-public class MainActivity extends Activity {
- private static final String TAG = "OSU_MainActivity";
- private OsuService mService;
-
- @Override
- protected void onCreate(Bundle saveInstanceState) {
- super.onCreate(saveInstanceState);
-
- Intent intent = getIntent();
- if (intent == null) {
- Log.e(TAG, "Intent not provided");
- finish();
- }
-
- if (!intent.hasExtra(Constants.INTENT_EXTRA_COMMAND)) {
- Log.e(TAG, "Command not provided");
- finish();
- }
-
- String command = intent.getStringExtra(Constants.INTENT_EXTRA_COMMAND);
- switch (command) {
- case Constants.COMMAND_PROVISION:
- if (!startProvisionService(intent.getParcelableExtra(
- Constants.INTENT_EXTRA_OSU_PROVIDER))) {
- finish();
- }
- break;
- default:
- Log.e(TAG, "Unknown command: '" + command + "'");
- finish();
- break;
- }
- }
-
- /**
- * Start the {@link ProvisionService} to perform provisioning tasks.
- *
- * @return true if service is started
- */
- private boolean startProvisionService(OsuProvider provider) {
- if (provider == null) {
- Log.e(TAG, "OSU Provider not provided");
- return false;
- }
- mService = new ProvisionService(this, provider);
- mService.start();
- return true;
- }
-}
diff --git a/packages/Osu2/src/com/android/osu/NetworkConnection.java b/packages/Osu2/src/com/android/osu/NetworkConnection.java
deleted file mode 100644
index 9f5b929e96d3..000000000000
--- a/packages/Osu2/src/com/android/osu/NetworkConnection.java
+++ /dev/null
@@ -1,206 +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 com.android.osu;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.Network;
-import android.net.NetworkInfo;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.net.wifi.WifiSsid;
-import android.os.Handler;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.io.IOException;
-
-/**
- * Responsible for setup/monitor on a Wi-Fi connection.
- */
-public class NetworkConnection {
- private static final String TAG = "OSU_NetworkConnection";
-
- private final WifiManager mWifiManager;
- private final Callbacks mCallbacks;
- private final int mNetworkId;
- private boolean mConnected = false;
-
- /**
- * Callbacks on Wi-Fi connection state changes.
- */
- public interface Callbacks {
- /**
- * Invoked when network connection is established with IP connectivity.
- *
- * @param network {@link Network} associated with the connected network.
- */
- public void onConnected(Network network);
-
- /**
- * Invoked when the targeted network is disconnected.
- */
- public void onDisconnected();
-
- /**
- * Invoked when network connection is not established within the pre-defined timeout.
- */
- public void onTimeout();
- }
-
- /**
- * Create an instance of {@link NetworkConnection} for the specified Wi-Fi network.
- * The Wi-Fi network (specified by its SSID) will be added/enabled as part of this object
- * creation.
- *
- * {@link #teardown} will need to be invoked once you're done with this connection,
- * to remove the given Wi-Fi network from the framework.
- *
- * @param context The application context
- * @param handler The handler to dispatch the processing of received broadcast intents
- * @param ssid The SSID to connect to
- * @param nai The network access identifier associated with the AP
- * @param callbacks The callbacks to be invoked on network change events
- * @throws IOException when failed to add/enable the specified Wi-Fi network
- */
- public NetworkConnection(Context context, Handler handler, WifiSsid ssid, String nai,
- Callbacks callbacks) throws IOException {
- mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
- mCallbacks = callbacks;
- mNetworkId = connect(ssid, nai);
-
- // TODO(zqiu): setup alarm to timed out the connection attempt.
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
- BroadcastReceiver receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
- handleNetworkStateChanged(
- intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO),
- intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO));
- }
- }
- };
- // Provide a Handler so that the onReceive call will be run on the specified handler
- // thread instead of the main thread.
- context.registerReceiver(receiver, filter, null, handler);
- }
-
- /**
- * Teardown the network connection by removing the network.
- */
- public void teardown() {
- mWifiManager.removeNetwork(mNetworkId);
- }
-
- /**
- * Connect to a OSU Wi-Fi network specified by the given SSID. The security type of the Wi-Fi
- * network is either open or OSEN (OSU Server-only authenticated layer 2 Encryption Network).
- * When network access identifier is provided, OSEN is used.
- *
- * @param ssid The SSID to connect to
- * @param nai Network access identifier of the network
- *
- * @return unique ID associated with the network
- * @throws IOException
- */
- private int connect(WifiSsid ssid, String nai) throws IOException {
- WifiConfiguration config = new WifiConfiguration();
- config.SSID = "\"" + ssid.toString() + "\"";
- if (TextUtils.isEmpty(nai)) {
- config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
- } else {
- // TODO(zqiu): configuration setup for OSEN.
- }
- int networkId = mWifiManager.addNetwork(config);
- if (networkId < 0) {
- throw new IOException("Failed to add OSU network");
- }
- if (!mWifiManager.enableNetwork(networkId, true)) {
- throw new IOException("Failed to enable OSU network");
- }
- return networkId;
- }
-
- /**
- * Handle network state changed events.
- *
- * @param networkInfo {@link NetworkInfo} indicating the current network state
- * @param wifiInfo {@link WifiInfo} associated with the current network when connected
- */
- private void handleNetworkStateChanged(NetworkInfo networkInfo, WifiInfo wifiInfo) {
- if (networkInfo == null) {
- Log.e(TAG, "NetworkInfo not provided for network state changed event");
- return;
- }
- switch (networkInfo.getDetailedState()) {
- case CONNECTED:
- handleConnectedEvent(wifiInfo);
- break;
- case DISCONNECTED:
- handleDisconnectedEvent();
- break;
- default:
- Log.d(TAG, "Ignore uninterested state: " + networkInfo.getDetailedState());
- break;
- }
- }
-
- /**
- * Handle network connected event.
- *
- * @param wifiInfo {@link WifiInfo} associated with the current connection
- */
- private void handleConnectedEvent(WifiInfo wifiInfo) {
- if (mConnected) {
- // No-op if already connected.
- return;
- }
- if (wifiInfo == null) {
- Log.e(TAG, "WifiInfo not provided for connected event");
- return;
- }
- if (wifiInfo.getNetworkId() != mNetworkId) {
- return;
- }
- Network network = mWifiManager.getCurrentNetwork();
- if (network == null) {
- Log.e(TAG, "Current network is not set");
- return;
- }
- mConnected = true;
- mCallbacks.onConnected(network);
- }
-
- /**
- * Handle network disconnected event.
- */
- private void handleDisconnectedEvent() {
- if (!mConnected) {
- // No-op if not connected, most likely a disconnect event for a different network.
- return;
- }
- mConnected = false;
- mCallbacks.onDisconnected();
- }
-}
diff --git a/packages/Osu2/src/com/android/osu/OsuService.java b/packages/Osu2/src/com/android/osu/OsuService.java
deleted file mode 100644
index 46a3c843f1dd..000000000000
--- a/packages/Osu2/src/com/android/osu/OsuService.java
+++ /dev/null
@@ -1,33 +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 com.android.osu;
-
-/**
- * Abstraction for services that can be performed by the OSU app, such as provisioning,
- * subscription remediation, and etc.
- */
-public interface OsuService {
- /**
- * Start the service.
- */
- public void start();
-
- /**
- * Stop the service.
- */
- public void stop();
-}
diff --git a/packages/Osu2/src/com/android/osu/ProvisionService.java b/packages/Osu2/src/com/android/osu/ProvisionService.java
deleted file mode 100644
index b1d43b2b0ea9..000000000000
--- a/packages/Osu2/src/com/android/osu/ProvisionService.java
+++ /dev/null
@@ -1,119 +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 com.android.osu;
-
-import android.content.Context;
-import android.net.Network;
-import android.net.wifi.hotspot2.OsuProvider;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Log;
-
-import java.io.IOException;
-
-/**
- * Service responsible for performing Passpoint subscription provisioning tasks.
- * This service will run on a separate thread to avoid blocking on the Main thread.
- */
-public class ProvisionService implements OsuService {
- private static final String TAG = "OSU_ProvisionService";
- private static final int COMMAND_START = 1;
- private static final int COMMAND_STOP = 2;
-
- private final Context mContext;
- private final HandlerThread mHandlerThread;
- private final ServiceHandler mServiceHandler;
- private final OsuProvider mProvider;
-
- private boolean mStarted = false;
- private NetworkConnection mNetworkConnection = null;
-
- public ProvisionService(Context context, OsuProvider provider) {
- mContext = context;
- mProvider = provider;
- mHandlerThread = new HandlerThread(TAG);
- mHandlerThread.start();
- mServiceHandler = new ServiceHandler(mHandlerThread.getLooper());
- }
-
- @Override
- public void start() {
- mServiceHandler.sendMessage(mServiceHandler.obtainMessage(COMMAND_START));
- }
-
- @Override
- public void stop() {
- mServiceHandler.sendMessage(mServiceHandler.obtainMessage(COMMAND_STOP));
- }
-
- /**
- * Handler class for handling commands to the ProvisionService.
- */
- private final class ServiceHandler extends Handler {
- public ServiceHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case COMMAND_START:
- if (mStarted) {
- Log.e(TAG, "Service already started");
- return;
- }
- try {
- // Initiate network connection to the OSU AP.
- mNetworkConnection = new NetworkConnection(
- mContext, this, mProvider.getOsuSsid(),
- mProvider.getNetworkAccessIdentifier(), new NetworkCallbacks());
- mStarted = true;
- } catch (IOException e) {
- // TODO(zqiu): broadcast failure event via LocalBroadcastManager.
- }
- break;
- case COMMAND_STOP:
- if (!mStarted) {
- Log.e(TAG, "Service not started");
- return;
- }
- Log.e(TAG, "Stop provision service");
- break;
- default:
- Log.e(TAG, "Unknown command: " + msg.what);
- break;
- }
- }
- }
-
- private final class NetworkCallbacks implements NetworkConnection.Callbacks {
- @Override
- public void onConnected(Network network) {
- Log.d(TAG, "Connected to OSU AP");
- }
-
- @Override
- public void onDisconnected() {
- }
-
- @Override
- public void onTimeout() {
- }
- }
-}
diff --git a/packages/Osu2/tests/Android.mk b/packages/Osu2/tests/Android.mk
deleted file mode 100644
index 23db7a94434c..000000000000
--- a/packages/Osu2/tests/Android.mk
+++ /dev/null
@@ -1,44 +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.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_CERTIFICATE := platform
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-
-LOCAL_JACK_FLAGS := --multi-dex native
-
-LOCAL_PACKAGE_NAME := OsuTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_INSTRUMENTATION_FOR := Osu2
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- android-support-test \
- mockito-target-minus-junit4 \
- frameworks-base-testutils
-
-# Code coverage puts us over the dex limit, so enable multi-dex for coverage-enabled builds
-ifeq (true,$(EMMA_INSTRUMENT))
-LOCAL_JACK_FLAGS := --multi-dex native
-LOCAL_DX_FLAGS := --multi-dex
-endif # EMMA_INSTRUMENT
-
-include $(BUILD_PACKAGE)
diff --git a/packages/Osu2/tests/AndroidManifest.xml b/packages/Osu2/tests/AndroidManifest.xml
deleted file mode 100644
index e22c1122958a..000000000000
--- a/packages/Osu2/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- ~ 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
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.osu.tests">
-
- <application>
- <uses-library android:name="android.test.runner" />
- <activity android:label="OsuTestDummyLabel"
- android:name="OsuTestDummyName">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- </application>
-
- <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.osu"
- android:label="OSU App Tests">
- </instrumentation>
-
-</manifest>
diff --git a/packages/Osu2/tests/AndroidTest.xml b/packages/Osu2/tests/AndroidTest.xml
deleted file mode 100644
index 9514dab74401..000000000000
--- a/packages/Osu2/tests/AndroidTest.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?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.
--->
-<!-- This test config file is auto-generated. -->
-<configuration description="Runs OSU App Tests.">
- <option name="test-suite-tag" value="apct" />
- <option name="test-suite-tag" value="apct-instrumentation" />
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="Osu2.apk" />
- <option name="test-file-name" value="OsuTests.apk" />
- </target_preparer>
-
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="com.android.osu.tests" />
- <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
- </test>
-</configuration>
diff --git a/packages/Osu2/tests/README.md b/packages/Osu2/tests/README.md
deleted file mode 100644
index dbfa79c3d26f..000000000000
--- a/packages/Osu2/tests/README.md
+++ /dev/null
@@ -1,45 +0,0 @@
-# OSU Unit Tests
-This package contains unit tests for the OSU app based on the
-[Android Testing Support Library](http://developer.android.com/tools/testing-support-library/index.html).
-The test cases are built using the [JUnit](http://junit.org/) and [Mockito](http://mockito.org/)
-libraries.
-
-## Running Tests
-The easiest way to run tests is simply run
-
-```
-frameworks/base/packages/Osu2/tests/runtests.sh
-```
-
-`runtests.sh` will build the test project and all of its dependencies and push the APK to the
-connected device. It will then run the tests on the device.
-
-To enable syncing data to the device for first time after clean reflash:
-1. adb disable-verity
-2. adb reboot
-3. adb remount
-
-See below for a few example of options to limit which tests are run.
-See the
-[AndroidJUnitRunner Documentation](https://developer.android.com/reference/android/support/test/runner/AndroidJUnitRunner.html)
-for more details on the supported options.
-
-```
-runtests.sh -e package com.android.osu
-runtests.sh -e class com.android.osu.NetworkConnectionTest
-```
-
-If you manually build and push the test APK to the device you can run tests using
-
-```
-adb shell am instrument -w 'com.android.osu.tests/android.support.test.runner.AndroidJUnitRunner'
-```
-
-## Adding Tests
-Tests can be added by adding classes to the src directory. JUnit4 style test cases can
-be written by simply annotating test methods with `org.junit.Test`.
-
-## Debugging Tests
-If you are trying to debug why tests are not doing what you expected, you can add android log
-statements and use logcat to view them. The beginning and end of every tests is automatically logged
-with the tag `TestRunner`.
diff --git a/packages/Osu2/tests/runtests.sh b/packages/Osu2/tests/runtests.sh
deleted file mode 100755
index 3513f5b8fc64..000000000000
--- a/packages/Osu2/tests/runtests.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/env bash
-
-if [ -z $ANDROID_BUILD_TOP ]; then
- echo "You need to source and lunch before you can use this script"
- exit 1
-fi
-
-echo "Running tests"
-
-set -e # fail early
-
-echo "+ mmma -j32 $ANDROID_BUILD_TOP/frameworks/base/packages/Osu2/tests"
-# NOTE Don't actually run the command above since this shell doesn't inherit functions from the
-# caller.
-make -j32 -C $ANDROID_BUILD_TOP -f build/core/main.mk MODULES-IN-frameworks-base-packages-Osu2-tests
-
-set -x # print commands
-
-adb root
-adb wait-for-device
-
-adb install -r -g "$OUT/data/app/OsuTests/OsuTests.apk"
-
-adb shell am instrument -w "$@" 'com.android.osu.tests/android.support.test.runner.AndroidJUnitRunner'
diff --git a/packages/Osu2/tests/src/com/android/osu/NetworkConnectionTest.java b/packages/Osu2/tests/src/com/android/osu/NetworkConnectionTest.java
deleted file mode 100644
index 2753249aa32e..000000000000
--- a/packages/Osu2/tests/src/com/android/osu/NetworkConnectionTest.java
+++ /dev/null
@@ -1,132 +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 com.android.osu;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import static org.mockito.MockitoAnnotations.initMocks;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkInfo;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.net.wifi.WifiSsid;
-import android.os.Handler;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-
-import java.io.IOException;
-
-/**
- * Unit tests for {@link com.android.osu.NetworkConnection}.
- */
-@SmallTest
-public class NetworkConnectionTest {
- private static final String TEST_SSID = "TEST SSID";
- private static final String TEST_SSID_WITH_QUOTES = "\"" + TEST_SSID + "\"";
- private static final int TEST_NETWORK_ID = 1;
-
- @Mock Context mContext;
- @Mock Handler mHandler;
- @Mock WifiManager mWifiManager;
- @Mock NetworkConnection.Callbacks mCallbacks;
-
- @Before
- public void setUp() throws Exception {
- initMocks(this);
- when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager);
- }
-
- /**
- * Verify that an IOException will be thrown when failed to add the network.
- *
- * @throws Exception
- */
- @Test(expected = IOException.class)
- public void networkAddFailed() throws Exception {
- when(mWifiManager.addNetwork(any(WifiConfiguration.class))).thenReturn(-1);
- new NetworkConnection(mContext, mHandler, WifiSsid.createFromAsciiEncoded(TEST_SSID),
- null, mCallbacks);
- }
-
- /**
- * Verify that an IOException will be thrown when failed to enable the network.
- *
- * @throws Exception
- */
- @Test(expected = IOException.class)
- public void networkEnableFailed() throws Exception {
- when(mWifiManager.addNetwork(any(WifiConfiguration.class))).thenReturn(TEST_NETWORK_ID);
- when(mWifiManager.enableNetwork(eq(TEST_NETWORK_ID), eq(true))).thenReturn(false);
- new NetworkConnection(mContext, mHandler, WifiSsid.createFromAsciiEncoded(TEST_SSID),
- null, mCallbacks);
- }
-
- /**
- * Verify that the connection is established after receiving a
- * WifiManager.NETWORK_STATE_CHANGED_ACTION intent indicating that we are connected.
- *
- * @throws Exception
- */
- @Test
- public void openNetworkConnectionEstablished() throws Exception {
- when(mWifiManager.addNetwork(any(WifiConfiguration.class))).thenReturn(TEST_NETWORK_ID);
- when(mWifiManager.enableNetwork(eq(TEST_NETWORK_ID), eq(true))).thenReturn(true);
- NetworkConnection connection = new NetworkConnection(mContext, mHandler,
- WifiSsid.createFromAsciiEncoded(TEST_SSID), null, mCallbacks);
-
- // Verify the WifiConfiguration being added.
- ArgumentCaptor<WifiConfiguration> wifiConfig =
- ArgumentCaptor.forClass(WifiConfiguration.class);
- verify(mWifiManager).addNetwork(wifiConfig.capture());
- assertEquals(wifiConfig.getValue().SSID, TEST_SSID_WITH_QUOTES);
-
- // Capture the BroadcastReceiver.
- ArgumentCaptor<BroadcastReceiver> receiver =
- ArgumentCaptor.forClass(BroadcastReceiver.class);
- verify(mContext).registerReceiver(receiver.capture(), any(), any(), any());
-
- // Setup intent.
- Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
- NetworkInfo networkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
- networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", "");
- intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
- WifiInfo wifiInfo = new WifiInfo();
- wifiInfo.setNetworkId(TEST_NETWORK_ID);
- intent.putExtra(WifiManager.EXTRA_WIFI_INFO, wifiInfo);
-
- // Send intent to the receiver.
- Network network = new Network(0);
- when(mWifiManager.getCurrentNetwork()).thenReturn(network);
- receiver.getValue().onReceive(mContext, intent);
-
- // Verify we are connected.
- verify(mCallbacks).onConnected(eq(network));
- }
-}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1d3e521fe80a..32aafeafb203 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2935,7 +2935,7 @@ public class SettingsProvider extends ContentProvider {
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 164;
+ private static final int SETTINGS_VERSION = 165;
private final int mUserId;
@@ -3710,17 +3710,7 @@ public class SettingsProvider extends ContentProvider {
}
if (currentVersion == 162) {
- // Version 162: Add a gesture for silencing phones
- final SettingsState settings = getGlobalSettingsLocked();
- final Setting currentSetting = settings.getSettingLocked(
- Global.SHOW_ZEN_UPGRADE_NOTIFICATION);
- if (!currentSetting.isNull()
- && TextUtils.equals("0", currentSetting.getValue())) {
- settings.insertSettingLocked(
- Global.SHOW_ZEN_UPGRADE_NOTIFICATION, "1",
- null, true, SettingsState.SYSTEM_PACKAGE_NAME);
- }
-
+ // Version 162: REMOVED: Add a gesture for silencing phones
currentVersion = 163;
}
@@ -3742,6 +3732,21 @@ public class SettingsProvider extends ContentProvider {
currentVersion = 164;
}
+ if (currentVersion == 164) {
+ // Version 164: Add a gesture for silencing phones
+ final SettingsState settings = getGlobalSettingsLocked();
+ final Setting currentSetting = settings.getSettingLocked(
+ Global.SHOW_ZEN_UPGRADE_NOTIFICATION);
+ if (!currentSetting.isNull()
+ && TextUtils.equals("0", currentSetting.getValue())) {
+ settings.insertSettingLocked(
+ Global.SHOW_ZEN_UPGRADE_NOTIFICATION, "1",
+ null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+
+ currentVersion = 165;
+ }
+
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index b5407dc0fd3a..d53f1a02b514 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -607,5 +607,6 @@
<action android:name="com.android.intent.action.SHOW_KEYBOARD_SHORTCUTS" />
</intent-filter>
</receiver>
+
</application>
</manifest>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml b/packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml
index 3193101a8322..87983b9186db 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml
@@ -20,39 +20,54 @@
<!-- This is a view that shows general status information in Keyguard. -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/res-auto"
android:id="@+id/presentation"
android:layout_width="match_parent"
android:layout_height="match_parent">
-
+ <!-- This is mostly keyguard_status_view.xml with minor modifications -->
<com.android.keyguard.KeyguardStatusView
android:id="@+id/clock"
android:orientation="vertical"
- android:layout_width="wrap_content"
+ android:layout_width="410dp"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal|top"
- android:orientation="vertical"
- android:focusable="true">
- <TextClock
- android:id="@+id/clock_view"
- android:layout_width="wrap_content"
+ android:orientation="vertical">
+ <RelativeLayout
+ android:id="@+id/keyguard_clock_container"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal|top"
- android:textColor="?attr/wallpaperTextColor"
- android:singleLine="true"
- style="@style/widget_big_thin"
- android:format12Hour="@string/keyguard_widget_12_hours_format"
- android:format24Hour="@string/keyguard_widget_24_hours_format"
- android:baselineAligned="true" />
-
- <include layout="@layout/keyguard_status_area" />
+ android:layout_gravity="center_horizontal|top">
+ <TextClock
+ android:id="@+id/clock_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_centerHorizontal="true"
+ android:layout_alignParentTop="true"
+ android:letterSpacing="0.03"
+ android:textColor="?attr/wallpaperTextColor"
+ android:singleLine="true"
+ style="@style/widget_big_thin"
+ android:format12Hour="@string/keyguard_widget_12_hours_format"
+ android:format24Hour="@string/keyguard_widget_24_hours_format" />
+ <View
+ android:id="@+id/clock_separator"
+ android:layout_width="@dimen/widget_separator_width"
+ android:layout_height="@dimen/widget_separator_thickness"
+ android:layout_below="@id/clock_view"
+ android:background="#f00"
+ android:layout_centerHorizontal="true" />
+ <include layout="@layout/keyguard_status_area"
+ android:id="@+id/keyguard_status_area"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/clock_separator" />
+ </RelativeLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="10dip"
+ android:layout_marginTop="@dimen/widget_vertical_padding"
android:layout_gravity="center_horizontal"
android:src="@drawable/kg_security_lock_normal" />
</LinearLayout>
diff --git a/packages/SystemUI/res/drawable/ic_memory.xml b/packages/SystemUI/res/drawable/ic_memory.xml
new file mode 100644
index 000000000000..ada36c58ff1d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_memory.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="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M16.0,5.0l-8.0,0.0l0.0,14.0l8.0,0.0z"
+ android:fillAlpha="0.5"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M6,9 L6,7 L4,7 L4,5 L6,5 C6,3.9 6.9,3 8,3 L16,3 C17.1,3 18,3.9 18,5 L20,5 L20,7 L18,7 L18,9 L20,9 L20,11 L18,11 L18,13 L20,13 L20,15 L18,15 L18,17 L20,17 L20,19 L18,19 C18,20.1 17.1,21 16,21 L8,21 C6.9,21 6,20.1 6,19 L4,19 L4,17 L6,17 L6,15 L4,15 L4,13 L6,13 L6,11 L4,11 L4,9 L6,9 Z M16,19 L16,5 L8,5 L8,19 L16,19 Z"
+ android:fillColor="#000000"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/smart_reply_button_background.xml b/packages/SystemUI/res/drawable/smart_reply_button_background.xml
index c464ba643897..93adaa00e73c 100644
--- a/packages/SystemUI/res/drawable/smart_reply_button_background.xml
+++ b/packages/SystemUI/res/drawable/smart_reply_button_background.xml
@@ -21,9 +21,9 @@
<item>
<inset
android:insetLeft="0dp"
- android:insetTop="7dp"
+ android:insetTop="8dp"
android:insetRight="0dp"
- android:insetBottom="5dp">
+ android:insetBottom="8dp">
<shape android:shape="rectangle">
<corners android:radius="8dp" />
<stroke android:width="1dp" android:color="@color/smart_reply_button_stroke" />
diff --git a/packages/SystemUI/res/layout/app_ops_info.xml b/packages/SystemUI/res/layout/app_ops_info.xml
index 74a4c6e3dee4..676301e8cc8a 100644
--- a/packages/SystemUI/res/layout/app_ops_info.xml
+++ b/packages/SystemUI/res/layout/app_ops_info.xml
@@ -21,6 +21,8 @@
android:layout_height="wrap_content"
android:id="@+id/app_ops_info"
android:clickable="true"
+ android:clipChildren="false"
+ android:clipToPadding="false"
android:orientation="vertical"
android:paddingStart="@*android:dimen/notification_content_margin_start"
android:paddingEnd="@*android:dimen/notification_content_margin_end"
@@ -63,10 +65,10 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal"
android:layout_marginTop="@dimen/notification_guts_button_spacing"
android:layout_marginBottom="@dimen/notification_guts_button_spacing"
- android:gravity="end" >
+ android:gravity="end"
+ android:orientation="horizontal">
<TextView
android:id="@+id/settings"
diff --git a/packages/SystemUI/res/layout/menu_ime.xml b/packages/SystemUI/res/layout/menu_ime.xml
index 5a0e76799e7c..1be3375b5c07 100644
--- a/packages/SystemUI/res/layout/menu_ime.xml
+++ b/packages/SystemUI/res/layout/menu_ime.xml
@@ -16,6 +16,7 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/menu_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index b1cb6cf91cb8..095f181fc049 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -17,10 +17,12 @@
<com.android.systemui.statusbar.NotificationInfo
xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/notification_guts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:id="@+id/notification_guts"
android:clickable="true"
+ android:clipChildren="false"
+ android:clipToPadding="false"
android:orientation="vertical"
android:paddingStart="@*android:dimen/notification_content_margin_start"
android:paddingEnd="@*android:dimen/notification_content_margin_end"
@@ -33,8 +35,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
- android:clipToPadding="false"
- android:layout_marginTop="2dp" >
+ android:clipToPadding="false">
<ImageView
android:id="@+id/pkgicon"
android:layout_width="@dimen/notification_guts_header_height"
@@ -74,16 +75,16 @@
android:layout_toEndOf="@id/pkg_group_divider" />
<ImageButton
android:id="@+id/info"
- android:src="@drawable/ic_info"
- android:tint="?android:attr/colorAccent"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:padding="12dp"
- android:layout_marginEnd="-12dp"
+ android:layout_width="56dp"
+ android:layout_height="56dp"
+ android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
- android:contentDescription="@string/notification_more_settings"
+ android:layout_marginEnd="-16dp"
android:background="@drawable/ripple_drawable"
- android:layout_alignParentEnd="true" />
+ android:contentDescription="@string/notification_more_settings"
+ android:padding="16dp"
+ android:src="@drawable/ic_info"
+ android:tint="?android:attr/colorAccent" />
</RelativeLayout>
<LinearLayout
@@ -91,7 +92,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/notification_guts_button_spacing"
- android:layout_marginTop="@*android:dimen/notification_header_padding_top"
+ android:clipChildren="false"
+ android:clipToPadding="false"
android:orientation="vertical">
<!-- Channel Info Block -->
@@ -105,14 +107,13 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:layout_marginBottom="6dp"
- style="@style/TextAppearance.NotificationInfo.Primary" />
+ style="@android:style/TextAppearance.Material.Notification.Title" />
<!-- Question prompt -->
<TextView
android:id="@+id/block_prompt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- style="@style/TextAppearance.NotificationInfo.Secondary" />
+ style="@android:style/TextAppearance.Material.Notification" />
</LinearLayout>
<!-- Settings and Done buttons -->
@@ -139,12 +140,14 @@
android:text="@string/inline_stop_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
+ android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
style="@style/TextAppearance.NotificationInfo.Button"/>
<TextView
android:id="@+id/minimize"
android:text="@string/inline_minimize_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
+ android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
style="@style/TextAppearance.NotificationInfo.Button" />
<TextView
android:id="@+id/keep"
@@ -152,6 +155,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginEnd="-8dp"
+ android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
style="@style/TextAppearance.NotificationInfo.Button"/>
</LinearLayout>
</LinearLayout>
@@ -160,22 +164,24 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/notification_guts_button_spacing"
- android:layout_marginTop="@*android:dimen/notification_header_padding_top"
+ android:layout_marginTop="@dimen/notification_guts_button_spacing"
android:visibility="gone"
android:orientation="horizontal" >
<TextView
android:id="@+id/confirmation_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
android:text="@string/notification_channel_disabled"
style="@style/TextAppearance.NotificationInfo.Confirmation"/>
<TextView
android:id="@+id/undo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/inline_undo"
android:layout_alignParentEnd="true"
+ android:layout_centerVertical="true"
android:layout_marginEnd="-8dp"
+ android:text="@string/inline_undo"
style="@style/TextAppearance.NotificationInfo.Button"/>
</RelativeLayout>
</com.android.systemui.statusbar.NotificationInfo>
diff --git a/packages/SystemUI/res/layout/qs_paged_page.xml b/packages/SystemUI/res/layout/qs_paged_page.xml
index 25b1a2b79a1c..07f0c83e7b2e 100644
--- a/packages/SystemUI/res/layout/qs_paged_page.xml
+++ b/packages/SystemUI/res/layout/qs_paged_page.xml
@@ -20,7 +20,7 @@
android:id="@+id/tile_page"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingLeft="@dimen/notification_side_paddings"
- android:paddingRight="@dimen/notification_side_paddings"
+ android:paddingStart="@dimen/notification_side_paddings"
+ android:paddingEnd="@dimen/notification_side_paddings"
android:clipChildren="false"
android:clipToPadding="false" />
diff --git a/packages/SystemUI/res/layout/smart_reply_button.xml b/packages/SystemUI/res/layout/smart_reply_button.xml
index 98e6e8227e4c..a490c4b8ba60 100644
--- a/packages/SystemUI/res/layout/smart_reply_button.xml
+++ b/packages/SystemUI/res/layout/smart_reply_button.xml
@@ -26,7 +26,7 @@
android:paddingVertical="@dimen/smart_reply_button_padding_vertical"
android:background="@drawable/smart_reply_button_background"
android:gravity="center"
- android:fontFamily="sans-serif-medium"
+ android:fontFamily="roboto-medium"
android:textSize="@dimen/smart_reply_button_font_size"
android:lineSpacingExtra="@dimen/smart_reply_button_line_spacing_extra"
android:textColor="@color/smart_reply_button_text"
diff --git a/packages/SystemUI/res/layout/status_bar_dnd_suppressing_notifications.xml b/packages/SystemUI/res/layout/status_bar_dnd_suppressing_notifications.xml
new file mode 100644
index 000000000000..eff9b3672889
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_dnd_suppressing_notifications.xml
@@ -0,0 +1,34 @@
+<!--
+ 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.
+-->
+
+<!-- Extends Framelayout -->
+<com.android.systemui.statusbar.DndSuppressingNotificationsView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/hidden_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone">
+ <TextView
+ android:id="@+id/hidden_notifications"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="64dp"
+ android:paddingTop="28dp"
+ android:gravity="top|center_horizontal"
+ android:textColor="?attr/wallpaperTextColor"
+ android:textSize="16sp"
+ android:text="@string/dnd_suppressing_shade_text"/>
+</com.android.systemui.statusbar.DndSuppressingNotificationsView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_footer.xml b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
index 22f1618f5474..b4c2ba86660d 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_footer.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
@@ -19,7 +19,8 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingEnd="8dp"
+ android:paddingStart="4dp"
+ android:paddingEnd="4dp"
android:visibility="gone">
<FrameLayout
android:id="@+id/content"
diff --git a/packages/SystemUI/res/layout/status_bar_wifi_group.xml b/packages/SystemUI/res/layout/status_bar_wifi_group.xml
index 482f78028497..c419b907ab17 100644
--- a/packages/SystemUI/res/layout/status_bar_wifi_group.xml
+++ b/packages/SystemUI/res/layout/status_bar_wifi_group.xml
@@ -28,8 +28,8 @@
android:id="@+id/wifi_group"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:paddingStart="2dp"
android:gravity="center_vertical"
+ android:layout_marginStart="2.5dp"
>
<FrameLayout
android:id="@+id/inout_container"
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index fd25c40bf0ed..efcca63c6d08 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -95,7 +95,7 @@
<color name="notification_gear_color">#ff757575</color>
<!-- The "inside" of a notification, reached via longpress -->
- <color name="notification_guts_bg_color">#eeeeee</color>
+ <color name="notification_guts_bg_color">#f8f9fa</color>
<color name="assist_orb_color">#ffffff</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 88e3331ff76c..b9cde7c31338 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -491,4 +491,6 @@
This name is in the ComponentName flattened format (package/class) -->
<string name="config_screenshotEditor" translatable="false"></string>
+ <!-- On debuggable builds, alert the user if SystemUI PSS goes over this number (in kb) -->
+ <integer name="watch_heap_limit">256000</integer>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 438d2f515a78..af343fb6a323 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -158,8 +158,17 @@
<!-- The space around a notification menu item -->
<dimen name="notification_menu_icon_padding">20dp</dimen>
- <!-- The veritical space around the buttons in the inline settings -->
- <dimen name="notification_guts_button_spacing">20dp</dimen>
+ <!-- The vertical space around the buttons in the inline settings -->
+ <dimen name="notification_guts_button_spacing">6dp</dimen>
+
+ <!-- The vertical padding a notification guts button has to fulfill the 48dp touch target -->
+ <dimen name="notification_guts_button_vertical_padding">14dp</dimen>
+
+ <!-- The horizontal padding for notification guts buttons-->
+ <dimen name="notification_guts_button_horizontal_padding">14dp</dimen>
+
+ <!-- The horizontal space around the buttons in the inline settings -->
+ <dimen name="notification_guts_button_horizontal_spacing">8dp</dimen>
<!-- The height of the header in inline settings -->
<dimen name="notification_guts_header_height">24dp</dimen>
@@ -930,12 +939,13 @@
<!-- Home button padding for sizing -->
<dimen name="home_padding">16dp</dimen>
- <!-- Smart reply button -->
+ <!-- Smart reply button. Total height 48dp, visible height 32dp. -->
<dimen name="smart_reply_button_spacing">8dp</dimen>
- <dimen name="smart_reply_button_padding_vertical">10dp</dimen>
- <dimen name="smart_reply_button_padding_horizontal_single_line">16dp</dimen>
- <dimen name="smart_reply_button_padding_horizontal_double_line">16dp</dimen>
- <dimen name="smart_reply_button_min_height">32dp</dimen>
+ <dimen name="smart_reply_button_padding_vertical">14dp</dimen>
+ <!-- Note: The following two paddings need to be different until b/78876518 is fixed. -->
+ <dimen name="smart_reply_button_padding_horizontal_single_line">20dp</dimen>
+ <dimen name="smart_reply_button_padding_horizontal_double_line">19dp</dimen>
+ <dimen name="smart_reply_button_min_height">48dp</dimen>
<dimen name="smart_reply_button_font_size">14sp</dimen>
<dimen name="smart_reply_button_line_spacing_extra">6sp</dimen> <!-- Total line height 20sp. -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 697ab06afb19..1b4b15e50902 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -240,6 +240,8 @@
<string name="accessibility_waiting_for_fingerprint">Waiting for fingerprint</string>
<!-- Accessibility action of the unlock button when fingerpint is on (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_unlock_without_fingerprint">Unlock without using your fingerprint</string>
+ <!-- Content description of the Trusted Face icon for accessibility. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_scanning_face">Scanning face</string>
<!-- Click action label for accessibility for the smart reply buttons (not shown on-screen).". [CHAR LIMIT=NONE] -->
<string name="accessibility_send_smart_reply">Send</string>
<!-- Click action label for accessibility for the unlock button. [CHAR LIMIT=NONE] -->
@@ -1062,7 +1064,7 @@
<string name="manage_notifications_text">Manage notifications</string>
<!-- The text to show in the notifications shade when dnd is suppressing notifications. [CHAR LIMIT=100] -->
- <string name="dnd_suppressing_shade_text">Do Not Disturb is hiding notifications</string>
+ <string name="dnd_suppressing_shade_text">Notifications hidden by Do Not Disturb</string>
<!-- Media projection permission dialog action text. [CHAR LIMIT=60] -->
<string name="media_projection_action_text">Start now</string>
@@ -2225,4 +2227,9 @@
<!-- URl of the webpage that explains battery saver. -->
<string name="help_uri_battery_saver_learn_more_link_target" translatable="false"></string>
+
+ <!-- Name for a quick settings tile, used only by platform developers, to extract the SystemUI process memory and send it to another
+ app for debugging. Will not be seen by users. [CHAR LIMIT=20] -->
+ <string name="heap_dump_tile_name">Dump SysUI Heap</string>
+
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 1e195344a6d3..c73da3c267ee 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -483,8 +483,10 @@
<item name="android:background">@drawable/btn_borderless_rect</item>
<item name="android:gravity">center</item>
<item name="android:focusable">true</item>
- <item name="android:paddingStart">8dp</item>
- <item name="android:paddingEnd">8dp</item>
+ <item name="android:paddingTop">@dimen/notification_guts_button_vertical_padding</item>
+ <item name="android:paddingBottom">@dimen/notification_guts_button_vertical_padding</item>
+ <item name="android:paddingLeft">@dimen/notification_guts_button_horizontal_padding</item>
+ <item name="android:paddingRight">@dimen/notification_guts_button_horizontal_padding</item>
</style>
<style name="TextAppearance.HeadsUpStatusBarText"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/MetricsLoggerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/MetricsLoggerCompat.java
index e93e78d1754f..952c8aee2408 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/MetricsLoggerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/MetricsLoggerCompat.java
@@ -17,10 +17,12 @@
package com.android.systemui.shared.system;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
public class MetricsLoggerCompat {
private final MetricsLogger mMetricsLogger;
+ public static final int OVERVIEW_ACTIVITY = MetricsEvent.OVERVIEW_ACTIVITY;
public MetricsLoggerCompat() {
mMetricsLogger = new MetricsLogger();
@@ -37,4 +39,12 @@ public class MetricsLoggerCompat {
public void visible(int category) {
mMetricsLogger.visible(category);
}
+
+ public void hidden(int category) {
+ mMetricsLogger.hidden(category);
+ }
+
+ public void visibility(int category, boolean visible) {
+ mMetricsLogger.visibility(category, visible);
+ }
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
index 07b980ef3f5e..ed2f8310eff4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
@@ -26,6 +26,10 @@ import android.util.Log;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
+
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
import com.android.systemui.shared.recents.view.RecentsTransition;
@@ -58,6 +62,11 @@ public class WindowManagerWrapper {
public static final int TRANSIT_KEYGUARD_OCCLUDE = WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
public static final int TRANSIT_KEYGUARD_UNOCCLUDE = WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
+ public static final int NAV_BAR_POS_INVALID = -1;
+ public static final int NAV_BAR_POS_LEFT = NAV_BAR_LEFT;
+ public static final int NAV_BAR_POS_RIGHT = NAV_BAR_RIGHT;
+ public static final int NAV_BAR_POS_BOTTOM = NAV_BAR_BOTTOM;
+
public static final int ACTIVITY_TYPE_STANDARD = WindowConfiguration.ACTIVITY_TYPE_STANDARD;
public static final int WINDOWING_MODE_UNDEFINED = WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -141,4 +150,20 @@ public class WindowManagerWrapper {
Log.w(TAG, "Failed to set recents visibility");
}
}
+
+ /**
+ * @return The side of the screen where navigation bar is positioned.
+ * @see #NAV_BAR_POS_RIGHT
+ * @see #NAV_BAR_POS_LEFT
+ * @see #NAV_BAR_POS_BOTTOM
+ * @see #NAV_BAR_POS_INVALID
+ */
+ public int getNavBarPosition() {
+ try {
+ return WindowManagerGlobal.getWindowManagerService().getNavBarPosition();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get nav bar position");
+ }
+ return NAV_BAR_POS_INVALID;
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 7cc37c476e31..81cf3aef4bc8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -140,12 +140,6 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
mImm.hideSoftInputFromWindow(getWindowToken(), 0);
}
- @Override
- public void reset() {
- super.reset();
- mPasswordEntry.requestFocus();
- }
-
private void updateSwitchImeButton() {
// If there's more than one IME, enable the IME switcher button
final boolean wasVisible = mSwitchImeButton.getVisibility() == View.VISIBLE;
@@ -193,8 +187,6 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
// Set selected property on so the view can send accessibility events.
mPasswordEntry.setSelected(true);
- mPasswordEntry.requestFocus();
-
mSwitchImeButton = findViewById(R.id.switch_ime_button);
mSwitchImeButton.setOnClickListener(new OnClickListener() {
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 1d3f9a13c631..a2befefba79e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -23,13 +23,16 @@ import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
+import com.android.internal.annotations.VisibleForTesting;
+
/**
* A Pin based Keyguard input view
*/
public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
implements View.OnKeyListener, View.OnTouchListener {
- protected PasswordTextView mPasswordEntry;
+ @VisibleForTesting
+ PasswordTextView mPasswordEntry;
private View mOkButton;
private View mDeleteButton;
private View mButton0;
@@ -52,12 +55,6 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
}
@Override
- public void reset() {
- mPasswordEntry.requestFocus();
- super.reset();
- }
-
- @Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
// send focus to the password field
return mPasswordEntry.requestFocus(direction, previouslyFocusedRect);
@@ -238,6 +235,12 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
}
@Override
+ public void onResume(int reason) {
+ super.onResume(reason);
+ mPasswordEntry.requestFocus();
+ }
+
+ @Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
doHapticKeyClick();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index ce34d0b3b7cc..454528e4f5f6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -82,14 +82,14 @@ public class KeyguardStatusView extends GridLayout implements
@Override
public void onTimeChanged() {
- refresh();
+ refreshTime();
}
@Override
public void onKeyguardVisibilityChanged(boolean showing) {
if (showing) {
if (DEBUG) Slog.v(TAG, "refresh statusview showing:" + showing);
- refresh();
+ refreshTime();
updateOwnerInfo();
updateLogoutView();
}
@@ -107,7 +107,7 @@ public class KeyguardStatusView extends GridLayout implements
@Override
public void onUserSwitchComplete(int userId) {
- refresh();
+ refreshFormat();
updateOwnerInfo();
updateLogoutView();
}
@@ -164,7 +164,9 @@ public class KeyguardStatusView extends GridLayout implements
protected void onFinishInflate() {
super.onFinishInflate();
mLogoutView = findViewById(R.id.logout);
- mLogoutView.setOnClickListener(this::onLogoutClicked);
+ if (mLogoutView != null) {
+ mLogoutView.setOnClickListener(this::onLogoutClicked);
+ }
mClockView = findViewById(R.id.clock_view);
mClockView.setShowCurrentUserTime(true);
@@ -184,7 +186,7 @@ public class KeyguardStatusView extends GridLayout implements
boolean shouldMarquee = KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive();
setEnableMarquee(shouldMarquee);
- refresh();
+ refreshFormat();
updateOwnerInfo();
updateLogoutView();
updateDark();
@@ -289,12 +291,16 @@ public class KeyguardStatusView extends GridLayout implements
mClockView.refresh();
}
- private void refresh() {
+ private void refreshFormat() {
Patterns.update(mContext);
- refreshTime();
+ mClockView.setFormat12Hour(Patterns.clockView12);
+ mClockView.setFormat24Hour(Patterns.clockView24);
}
public int getLogoutButtonHeight() {
+ if (mLogoutView == null) {
+ return 0;
+ }
return mLogoutView.getVisibility() == VISIBLE ? mLogoutView.getHeight() : 0;
}
@@ -303,6 +309,9 @@ public class KeyguardStatusView extends GridLayout implements
}
private void updateLogoutView() {
+ if (mLogoutView == null) {
+ return;
+ }
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(
@@ -338,6 +347,11 @@ public class KeyguardStatusView extends GridLayout implements
}
@Override
+ public void onLocaleListChanged() {
+ refreshFormat();
+ }
+
+ @Override
public boolean hasOverlappingRendering() {
return false;
}
@@ -384,7 +398,9 @@ public class KeyguardStatusView extends GridLayout implements
private void updateDark() {
boolean dark = mDarkAmount == 1;
- mLogoutView.setAlpha(dark ? 0 : 1);
+ if (mLogoutView != null) {
+ mLogoutView.setAlpha(dark ? 0 : 1);
+ }
if (mOwnerInfo != null) {
boolean hasText = !TextUtils.isEmpty(mOwnerInfo.getText());
mOwnerInfo.setVisibility(hasText && mDarkAmount != 1 ? VISIBLE : GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 7d19784aad03..beb3c5398780 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -247,10 +247,14 @@ public class Dependency extends SystemUI {
getDependency(LeakDetector.class),
getDependency(LEAK_REPORT_EMAIL)));
- mProviders.put(GarbageMonitor.class, () -> new GarbageMonitor(
- getDependency(BG_LOOPER),
- getDependency(LeakDetector.class),
- getDependency(LeakReporter.class)));
+ mProviders.put(
+ GarbageMonitor.class,
+ () ->
+ new GarbageMonitor(
+ mContext,
+ getDependency(BG_LOOPER),
+ getDependency(LeakDetector.class),
+ getDependency(LeakReporter.class)));
mProviders.put(TunerService.class, () ->
new TunerServiceImpl(mContext));
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index f595d776e8fe..a7163bbaac04 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -94,6 +94,8 @@ public final class Prefs {
String OVERVIEW_OPENED_FROM_HOME_COUNT = "OverviewOpenedFromHomeCount";
String HAS_SEEN_RECENTS_SWIPE_UP_ONBOARDING = "HasSeenRecentsSwipeUpOnboarding";
String HAS_SEEN_RECENTS_QUICK_SCRUB_ONBOARDING = "HasSeenRecentsQuickScrubOnboarding";
+ String HAS_DISMISSED_RECENTS_QUICK_SCRUB_ONBOARDING_ONCE =
+ "HasDismissedRecentsQuickScrubOnboardingOnce";
String SEEN_RINGER_GUIDANCE_COUNT = "RingerGuidanceCount";
String QS_TILE_SPECS_REVEALED = "QsTileSpecsRevealed";
String QS_HAS_TURNED_OFF_MOBILE_DATA = "QsHasTurnedOffMobileData";
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index a7975d7e4595..087d481a61f2 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -1380,6 +1380,15 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mHardwareLayout = HardwareUiLayout.get(mListView);
mHardwareLayout.setOutsideTouchListener(view -> dismiss());
setTitle(R.string.global_actions);
+ mListView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
+ @Override
+ public boolean dispatchPopulateAccessibilityEvent(
+ View host, AccessibilityEvent event) {
+ // Populate the title here, just as Activity does
+ event.getText().add(mContext.getString(R.string.global_actions));
+ return true;
+ }
+ });
}
private void updateList() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 6d46e857c8b4..45d63e0c1359 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -93,7 +93,8 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int numTiles = mRecords.size();
- final int width = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight;
+ final int width = MeasureSpec.getSize(widthMeasureSpec)
+ - getPaddingStart() - getPaddingEnd();
final int numRows = (numTiles + mColumns - 1) / mColumns;
mCellWidth = (width - mSidePadding * 2 - (mCellMarginHorizontal * mColumns)) / mColumns;
@@ -140,16 +141,8 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
final TileRecord record = mRecords.get(i);
final int top = getRowTop(row);
- final int right;
- final int left;
- if (isRtl) {
- right = w - getColumnStart(column);
- left = right - mCellWidth;
- } else {
- left = getColumnStart(column);
- right = left + mCellWidth;
- }
-
+ final int left = getColumnStart(isRtl ? mColumns - column - 1 : column);
+ final int right = left + mCellWidth;
record.tileView.layout(left, top, right, top + record.tileView.getMeasuredHeight());
}
}
@@ -159,6 +152,7 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
}
private int getColumnStart(int column) {
- return column * (mCellWidth + mCellMarginHorizontal) + mCellMarginHorizontal + mPaddingLeft;
+ return getPaddingStart() + mSidePadding + mCellMarginHorizontal / 2 +
+ column * (mCellWidth + mCellMarginHorizontal);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 9593b0fb9e9b..53a576d3519d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -24,6 +24,7 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Handler;
import android.service.quicksettings.TileService;
import android.text.TextUtils;
@@ -37,8 +38,10 @@ import com.android.systemui.plugins.qs.QSTile.State;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon;
+import com.android.systemui.util.leak.GarbageMonitor;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@@ -68,7 +71,6 @@ public class TileQueryHelper {
// Enqueue jobs to fetch every system tile and then ever package tile.
addStockTiles(host);
addPackageTiles(host);
- // TODO: Live?
}
public boolean isFinished() {
@@ -77,10 +79,14 @@ public class TileQueryHelper {
private void addStockTiles(QSTileHost host) {
String possible = mContext.getString(R.string.quick_settings_tiles_stock);
- String[] possibleTiles = possible.split(",");
+ final ArrayList<String> possibleTiles = new ArrayList<>();
+ possibleTiles.addAll(Arrays.asList(possible.split(",")));
+ if (Build.IS_DEBUGGABLE) {
+ possibleTiles.add(GarbageMonitor.MemoryTile.TILE_SPEC);
+ }
+
final ArrayList<QSTile> tilesToAdd = new ArrayList<>();
- for (int i = 0; i < possibleTiles.length; i++) {
- final String spec = possibleTiles[i];
+ for (String spec : possibleTiles) {
final QSTile tile = host.createTile(spec);
if (tile == null) {
continue;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 8d488903ad49..ac7ef5dc308e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -15,6 +15,7 @@
package com.android.systemui.qs.tileimpl;
import android.content.Context;
+import android.os.Build;
import android.util.Log;
import android.view.ContextThemeWrapper;
@@ -41,6 +42,7 @@ import com.android.systemui.qs.tiles.UserTile;
import com.android.systemui.qs.tiles.WifiTile;
import com.android.systemui.qs.tiles.WorkModeTile;
import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.util.leak.GarbageMonitor;
public class QSFactoryImpl implements QSFactory {
@@ -60,30 +62,58 @@ public class QSFactoryImpl implements QSFactory {
}
private QSTileImpl createTileInternal(String tileSpec) {
- if (tileSpec.equals("wifi")) return new WifiTile(mHost);
- else if (tileSpec.equals("bt")) return new BluetoothTile(mHost);
- else if (tileSpec.equals("cell")) return new CellularTile(mHost);
- else if (tileSpec.equals("dnd")) return new DndTile(mHost);
- else if (tileSpec.equals("inversion")) return new ColorInversionTile(mHost);
- else if (tileSpec.equals("airplane")) return new AirplaneModeTile(mHost);
- else if (tileSpec.equals("work")) return new WorkModeTile(mHost);
- else if (tileSpec.equals("rotation")) return new RotationLockTile(mHost);
- else if (tileSpec.equals("flashlight")) return new FlashlightTile(mHost);
- else if (tileSpec.equals("location")) return new LocationTile(mHost);
- else if (tileSpec.equals("cast")) return new CastTile(mHost);
- else if (tileSpec.equals("hotspot")) return new HotspotTile(mHost);
- else if (tileSpec.equals("user")) return new UserTile(mHost);
- else if (tileSpec.equals("battery")) return new BatterySaverTile(mHost);
- else if (tileSpec.equals("saver")) return new DataSaverTile(mHost);
- else if (tileSpec.equals("night")) return new NightDisplayTile(mHost);
- else if (tileSpec.equals("nfc")) return new NfcTile(mHost);
+ // Stock tiles.
+ switch (tileSpec) {
+ case "wifi":
+ return new WifiTile(mHost);
+ case "bt":
+ return new BluetoothTile(mHost);
+ case "cell":
+ return new CellularTile(mHost);
+ case "dnd":
+ return new DndTile(mHost);
+ case "inversion":
+ return new ColorInversionTile(mHost);
+ case "airplane":
+ return new AirplaneModeTile(mHost);
+ case "work":
+ return new WorkModeTile(mHost);
+ case "rotation":
+ return new RotationLockTile(mHost);
+ case "flashlight":
+ return new FlashlightTile(mHost);
+ case "location":
+ return new LocationTile(mHost);
+ case "cast":
+ return new CastTile(mHost);
+ case "hotspot":
+ return new HotspotTile(mHost);
+ case "user":
+ return new UserTile(mHost);
+ case "battery":
+ return new BatterySaverTile(mHost);
+ case "saver":
+ return new DataSaverTile(mHost);
+ case "night":
+ return new NightDisplayTile(mHost);
+ case "nfc":
+ return new NfcTile(mHost);
+ }
+
// Intent tiles.
- else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(mHost, tileSpec);
- else if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(mHost, tileSpec);
- else {
- Log.w(TAG, "Bad tile spec: " + tileSpec);
- return null;
+ if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(mHost, tileSpec);
+ if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(mHost, tileSpec);
+
+ // Debug tiles.
+ if (Build.IS_DEBUGGABLE) {
+ if (tileSpec.equals(GarbageMonitor.MemoryTile.TILE_SPEC)) {
+ return new GarbageMonitor.MemoryTile(mHost);
+ }
}
+
+ // Broken tiles.
+ Log.w(TAG, "Bad tile spec: " + tileSpec);
+ return null;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index ffa144415eac..31933d011518 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -19,6 +19,7 @@ package com.android.systemui.recents;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static com.android.systemui.Prefs.Key.HAS_DISMISSED_RECENTS_QUICK_SCRUB_ONBOARDING_ONCE;
import static com.android.systemui.Prefs.Key.HAS_SEEN_RECENTS_QUICK_SCRUB_ONBOARDING;
import static com.android.systemui.Prefs.Key.HAS_SEEN_RECENTS_SWIPE_UP_ONBOARDING;
import static com.android.systemui.Prefs.Key.OVERVIEW_OPENED_COUNT;
@@ -66,7 +67,7 @@ public class RecentsOnboarding {
private static final String TAG = "RecentsOnboarding";
private static final boolean RESET_PREFS_FOR_DEBUG = false;
- private static final boolean ONBOARDING_ENABLED = false;
+ private static final boolean ONBOARDING_ENABLED = true;
private static final long SHOW_DELAY_MS = 500;
private static final long SHOW_HIDE_DURATION_MS = 300;
// Show swipe-up tips after opening overview from home this number of times.
@@ -76,9 +77,6 @@ public class RecentsOnboarding {
// After explicitly dismissing, show again after launching this number of apps for swipe-up
// tips.
private static final int SWIPE_UP_SHOW_ON_APP_LAUNCH_AFTER_DISMISS = 5;
- // After explicitly dismissing, show again after launching this number of apps for QuickScrub
- // tips.
- private static final int QUICK_SCRUB_SHOW_ON_APP_LAUNCH_AFTER_DISMISS = 10;
private final Context mContext;
private final WindowManager mWindowManager;
@@ -99,7 +97,7 @@ public class RecentsOnboarding {
private boolean mHasDismissedSwipeUpTip;
private boolean mHasDismissedQuickScrubTip;
private int mNumAppsLaunchedSinceSwipeUpTipDismiss;
- private int mNumAppsLaunchedSinceQuickScrubTipDismiss;
+ private int mOverviewOpenedCountSinceQuickScrubTipDismiss;
private final SysUiTaskStackChangeListener mTaskListener = new SysUiTaskStackChangeListener() {
@Override
@@ -145,10 +143,9 @@ public class RecentsOnboarding {
} else {
if (getOpenedOverviewCount() >= QUICK_SCRUB_SHOW_ON_OVERVIEW_OPENED_COUNT) {
if (mHasDismissedQuickScrubTip) {
- mNumAppsLaunchedSinceQuickScrubTipDismiss++;
- if (mNumAppsLaunchedSinceQuickScrubTipDismiss
- == QUICK_SCRUB_SHOW_ON_APP_LAUNCH_AFTER_DISMISS) {
- mNumAppsLaunchedSinceQuickScrubTipDismiss = 0;
+ if (mOverviewOpenedCountSinceQuickScrubTipDismiss
+ == QUICK_SCRUB_SHOW_ON_OVERVIEW_OPENED_COUNT) {
+ mOverviewOpenedCountSinceQuickScrubTipDismiss = 0;
show(R.string.recents_quick_scrub_onboarding);
}
} else {
@@ -166,14 +163,19 @@ public class RecentsOnboarding {
new OverviewProxyService.OverviewProxyListener() {
@Override
public void onOverviewShown(boolean fromHome) {
- boolean alreadySeenRecentsOnboarding = hasSeenSwipeUpOnboarding();
- if (!alreadySeenRecentsOnboarding && !fromHome) {
+ if (!hasSeenSwipeUpOnboarding() && !fromHome) {
setHasSeenSwipeUpOnboarding(true);
}
if (fromHome) {
setOpenedOverviewFromHomeCount(getOpenedOverviewFromHomeCount() + 1);
}
setOpenedOverviewCount(getOpenedOverviewCount() + 1);
+
+ if (getOpenedOverviewCount() >= QUICK_SCRUB_SHOW_ON_OVERVIEW_OPENED_COUNT) {
+ if (mHasDismissedQuickScrubTip) {
+ mOverviewOpenedCountSinceQuickScrubTipDismiss++;
+ }
+ }
}
@Override
@@ -191,7 +193,11 @@ public class RecentsOnboarding {
public void onViewAttachedToWindow(View view) {
if (view == mLayout) {
mLayoutAttachedToWindow = true;
- mHasDismissedSwipeUpTip = false;
+ if (view.getTag().equals(R.string.recents_swipe_up_onboarding)) {
+ mHasDismissedSwipeUpTip = false;
+ } else {
+ mHasDismissedQuickScrubTip = false;
+ }
}
}
@@ -199,6 +205,17 @@ public class RecentsOnboarding {
public void onViewDetachedFromWindow(View view) {
if (view == mLayout) {
mLayoutAttachedToWindow = false;
+ if (view.getTag().equals(R.string.recents_quick_scrub_onboarding)) {
+ mHasDismissedQuickScrubTip = true;
+ if (hasDismissedQuickScrubOnboardingOnce()) {
+ // If user dismisses the quick scrub tip twice, we consider user has seen it
+ // and do not show it again.
+ setHasSeenQuickScrubOnboarding(true);
+ } else {
+ setHasDismissedQuickScrubOnboardingOnce(true);
+ }
+ mOverviewOpenedCountSinceQuickScrubTipDismiss = 0;
+ }
}
}
};
@@ -228,15 +245,6 @@ public class RecentsOnboarding {
if (v.getTag().equals(R.string.recents_swipe_up_onboarding)) {
mHasDismissedSwipeUpTip = true;
mNumAppsLaunchedSinceSwipeUpTipDismiss = 0;
- } else {
- if (mHasDismissedQuickScrubTip) {
- // If user dismisses the quick scrub tip twice, we consider user has seen it
- // and do not show it again.
- setHasSeenQuickScrubOnboarding(true);
- } else {
- mHasDismissedQuickScrubTip = true;
- }
- mNumAppsLaunchedSinceQuickScrubTipDismiss = 0;
}
});
@@ -252,6 +260,7 @@ public class RecentsOnboarding {
if (RESET_PREFS_FOR_DEBUG) {
setHasSeenSwipeUpOnboarding(false);
setHasSeenQuickScrubOnboarding(false);
+ setHasDismissedQuickScrubOnboardingOnce(false);
setOpenedOverviewCount(0);
setOpenedOverviewFromHomeCount(0);
}
@@ -289,7 +298,7 @@ public class RecentsOnboarding {
mHasDismissedSwipeUpTip = false;
mHasDismissedQuickScrubTip = false;
mNumAppsLaunchedSinceSwipeUpTipDismiss = 0;
- mNumAppsLaunchedSinceQuickScrubTipDismiss = 0;
+ mOverviewOpenedCountSinceQuickScrubTipDismiss = 0;
hide(false);
}
@@ -303,11 +312,15 @@ public class RecentsOnboarding {
if (!shouldShow()) {
return;
}
+ if (mLayoutAttachedToWindow) {
+ hide(false);
+ }
mDismissView.setTag(stringRes);
+ mLayout.setTag(stringRes);
mTextView.setText(stringRes);
// Only show in portrait.
int orientation = mContext.getResources().getConfiguration().orientation;
- if (!mLayoutAttachedToWindow && orientation == Configuration.ORIENTATION_PORTRAIT) {
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) {
mLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
mWindowManager.addView(mLayout, getWindowLayoutParams());
@@ -348,11 +361,11 @@ public class RecentsOnboarding {
.withLayer()
.setDuration(SHOW_HIDE_DURATION_MS)
.setInterpolator(new AccelerateInterpolator())
- .withEndAction(() -> mWindowManager.removeView(mLayout))
+ .withEndAction(() -> mWindowManager.removeViewImmediate(mLayout))
.start();
} else {
mLayout.animate().cancel();
- mWindowManager.removeView(mLayout);
+ mWindowManager.removeViewImmediate(mLayout);
}
}
}
@@ -400,6 +413,16 @@ public class RecentsOnboarding {
}
}
+ private boolean hasDismissedQuickScrubOnboardingOnce() {
+ return Prefs.getBoolean(mContext, HAS_DISMISSED_RECENTS_QUICK_SCRUB_ONBOARDING_ONCE, false);
+ }
+
+ private void setHasDismissedQuickScrubOnboardingOnce(
+ boolean hasDismissedQuickScrubOnboardingOnce) {
+ Prefs.putBoolean(mContext, HAS_DISMISSED_RECENTS_QUICK_SCRUB_ONBOARDING_ONCE,
+ hasDismissedQuickScrubOnboardingOnce);
+ }
+
private int getOpenedOverviewFromHomeCount() {
return Prefs.getInt(mContext, OVERVIEW_OPENED_FROM_HOME_COUNT, 0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 1149ad179b05..79fea9fa4228 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -21,6 +21,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECOND
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW;
import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -364,14 +366,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
if (mStableInsets.isEmpty()) {
SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets);
}
- int position = (int) (mState.mRatioPositionBeforeMinimized *
- (isHorizontalDivision() ? mDisplayHeight : mDisplayWidth));
- mSnapAlgorithm = null;
- initializeSnapAlgorithm();
-
- // Set the snap target before minimized but do not save until divider is attached and not
- // minimized because it does not know its minimized state yet.
- mSnapTargetBeforeMinimized = mSnapAlgorithm.calculateNonDismissingSnapTarget(position);
+ repositionSnapTargetBeforeMinimized();
}
public WindowManagerProxy getWindowManagerProxy() {
@@ -878,9 +873,36 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
public void notifyDockSideChanged(int newDockSide) {
+ int oldDockSide = mDockSide;
mDockSide = newDockSide;
mMinimizedShadow.setDockSide(mDockSide);
requestLayout();
+
+ // Update the snap position to the new docked side with correct insets
+ SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets);
+ mMinimizedSnapAlgorithm = null;
+ initializeSnapAlgorithm();
+
+ if (oldDockSide == DOCKED_LEFT && mDockSide == DOCKED_RIGHT
+ || oldDockSide == DOCKED_RIGHT && mDockSide == DOCKED_LEFT) {
+ repositionSnapTargetBeforeMinimized();
+ }
+
+ // Landscape to seascape rotation requires minimized to resize docked app correctly
+ if (mHomeStackResizable && mDockedStackMinimized) {
+ resizeStack(mMinimizedSnapAlgorithm.getMiddleTarget());
+ }
+ }
+
+ private void repositionSnapTargetBeforeMinimized() {
+ int position = (int) (mState.mRatioPositionBeforeMinimized *
+ (isHorizontalDivision() ? mDisplayHeight : mDisplayWidth));
+ mSnapAlgorithm = null;
+ initializeSnapAlgorithm();
+
+ // Set the snap target before minimized but do not save until divider is attached and not
+ // minimized because it does not know its minimized state yet.
+ mSnapTargetBeforeMinimized = mSnapAlgorithm.calculateNonDismissingSnapTarget(position);
}
private void updateDisplayInfo() {
@@ -962,6 +984,12 @@ public class DividerView extends FrameLayout implements OnTouchListener,
if (mHomeStackResizable && mIsInMinimizeInteraction) {
calculateBoundsForPosition(mSnapTargetBeforeMinimized.position, mDockSide,
mDockedTaskRect);
+
+ // Move a right-docked-app to line up with the divider while dragging it
+ if (mDockSide == DOCKED_RIGHT) {
+ mDockedTaskRect.offset(Math.max(position, mStableInsets.left - mDividerSize)
+ - mDockedTaskRect.left + mDividerSize, 0);
+ }
calculateBoundsForPosition(mSnapTargetBeforeMinimized.position,
DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect);
mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedTaskRect,
@@ -976,6 +1004,12 @@ public class DividerView extends FrameLayout implements OnTouchListener,
calculateBoundsForPosition(isHorizontalDivision() ? mDisplayHeight : mDisplayWidth,
mDockSide, mDockedTaskRect);
}
+
+ // Move a docked app if from the right in position with the divider up to insets
+ if (mDockSide == DOCKED_RIGHT) {
+ mDockedTaskRect.offset(Math.max(position,
+ mStableInsets.left) - mDockedTaskRect.left, 0);
+ }
calculateBoundsForPosition(taskPosition, DockedDividerUtils.invertDockSide(mDockSide),
mOtherTaskRect);
mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, null,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DndSuppressingNotificationsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/DndSuppressingNotificationsView.java
new file mode 100644
index 000000000000..db3a02dd4f95
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DndSuppressingNotificationsView.java
@@ -0,0 +1,91 @@
+/*
+ * 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.statusbar;
+
+import android.annotation.ColorInt;
+import android.annotation.DrawableRes;
+import android.annotation.IntegerRes;
+import android.annotation.StringRes;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Configuration;
+import android.graphics.drawable.Icon;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.stack.ExpandableViewState;
+import com.android.systemui.statusbar.stack.StackScrollState;
+
+public class DndSuppressingNotificationsView extends StackScrollerDecorView {
+
+ private TextView mText;
+ private @StringRes int mTextId = R.string.dnd_suppressing_shade_text;
+
+ public DndSuppressingNotificationsView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ mText.setText(mTextId);
+ }
+
+ @Override
+ protected View findContentView() {
+ return findViewById(R.id.hidden_container);
+ }
+
+ @Override
+ protected View findSecondaryView() {
+ return null;
+ }
+
+ public void setColor(@ColorInt int color) {
+ mText.setTextColor(color);
+ }
+
+ public void setOnContentClickListener(OnClickListener listener) {
+ mText.setOnClickListener(listener);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mText = findViewById(R.id.hidden_notifications);
+ }
+
+ @Override
+ public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
+ return new DndSuppressingViewState();
+ }
+
+ public class DndSuppressingViewState extends ExpandableViewState {
+ @Override
+ public void applyToView(View view) {
+ super.applyToView(view);
+ if (view instanceof DndSuppressingNotificationsView) {
+ DndSuppressingNotificationsView dndView = (DndSuppressingNotificationsView) view;
+ boolean visible = this.clipTopAmount <= mText.getPaddingTop() * 0.6f;
+ dndView.performVisibilityAnimation(visible && !dndView.willBeGone());
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 42c774ee0c5c..27fa48aee216 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -76,6 +76,7 @@ import com.android.systemui.statusbar.NotificationGuts.GutsContent;
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.HybridNotificationView;
+import com.android.systemui.statusbar.notification.NotificationCounters;
import com.android.systemui.statusbar.notification.NotificationInflater;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.NotificationViewWrapper;
@@ -1252,6 +1253,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
Dependency.get(NotificationBlockingHelperManager.class);
boolean isBlockingHelperShown = manager.perhapsShowBlockingHelper(this, mMenuRow);
+ Dependency.get(MetricsLogger.class).count(NotificationCounters.NOTIFICATION_DISMISSED, 1);
+
// Continue with dismiss since we don't want the blocking helper to be directly associated
// with a certain notification.
performDismiss(fromAccessibility);
@@ -1632,6 +1635,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mTranslateableViews.get(i).setTranslationX(0);
}
invalidateOutline();
+ getEntry().expandedIcon.setScrollX(0);
}
mMenuRow.resetMenu();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index df6a9778142f..29c3ebdae326 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -58,6 +58,7 @@ public abstract class ExpandableView extends FrameLayout {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int givenSize = MeasureSpec.getSize(heightMeasureSpec);
+ final int viewHorizontalPadding = getPaddingStart() + getPaddingEnd();
int ownMaxHeight = Integer.MAX_VALUE;
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (heightMode != MeasureSpec.UNSPECIFIED && givenSize != 0) {
@@ -80,8 +81,8 @@ public abstract class ExpandableView extends FrameLayout {
? MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.EXACTLY)
: MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
}
- child.measure(
- getChildMeasureSpec(widthMeasureSpec, 0 /* padding */, layoutParams.width),
+ child.measure(getChildMeasureSpec(
+ widthMeasureSpec, viewHorizontalPadding, layoutParams.width),
childHeightSpec);
int childHeight = child.getMeasuredHeight();
maxChildHeight = Math.max(maxChildHeight, childHeight);
@@ -94,7 +95,7 @@ public abstract class ExpandableView extends FrameLayout {
newHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY);
for (View child : mMatchParentViews) {
child.measure(getChildMeasureSpec(
- widthMeasureSpec, 0 /* padding */, child.getLayoutParams().width),
+ widthMeasureSpec, viewHorizontalPadding, child.getLayoutParams().width),
newHeightSpec);
}
mMatchParentViews.clear();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index bc572a2163d1..0cc6137182e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -30,6 +30,7 @@ import android.view.ViewAnimationUtils;
import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -270,7 +271,8 @@ public class NotificationGuts extends FrameLayout {
/** Animates out the guts view via either a fade or a circular reveal. */
- private void animateClose(int x, int y, boolean shouldDoCircularReveal) {
+ @VisibleForTesting
+ void animateClose(int x, int y, boolean shouldDoCircularReveal) {
if (shouldDoCircularReveal) {
// Circular reveal originating at (x, y)
if (x == -1 || y == -1) {
@@ -340,7 +342,8 @@ public class NotificationGuts extends FrameLayout {
}
}
- private void setExposed(boolean exposed, boolean needsFalsingProtection) {
+ @VisibleForTesting
+ void setExposed(boolean exposed, boolean needsFalsingProtection) {
final boolean wasExposed = mExposed;
mExposed = exposed;
mNeedsFalsingProtection = needsFalsingProtection;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 6a1740ca618c..ec49f436b7d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -54,17 +54,20 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.NotificationCounters;
import java.util.List;
/**
- * The guts of a notification revealed when performing a long press.
+ * The guts of a notification revealed when performing a long press. This also houses the blocking
+ * helper affordance that allows a user to keep/stop notifications after swiping one away.
*/
public class NotificationInfo extends LinearLayout implements NotificationGuts.GutsContent {
private static final String TAG = "InfoGuts";
private INotificationManager mINotificationManager;
private PackageManager mPm;
+ private MetricsLogger mMetricsLogger;
private String mPackageName;
private String mAppName;
@@ -84,17 +87,27 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
private OnAppSettingsClickListener mAppSettingsClickListener;
private NotificationGuts mGutsContainer;
- /** Whether this view is being shown as part of the blocking helper */
+ /** Whether this view is being shown as part of the blocking helper. */
private boolean mIsForBlockingHelper;
private boolean mNegativeUserSentiment;
- private OnClickListener mOnKeepShowing = this::closeControls;
+ /** Counter tag that describes how the user exit or quit out of this view. */
+ private String mExitReasonCounter = NotificationCounters.BLOCKING_HELPER_DISMISSED;
+
+ private OnClickListener mOnKeepShowing = v -> {
+ mExitReasonCounter = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
+ closeControls(v);
+ };
private OnClickListener mOnStopOrMinimizeNotifications = v -> {
+ mExitReasonCounter = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS;
swapContent(false);
};
private OnClickListener mOnUndo = v -> {
+ // Reset exit counter that we'll log and record an undo event separately (not an exit event)
+ mExitReasonCounter = NotificationCounters.BLOCKING_HELPER_DISMISSED;
+ logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_UNDO);
swapContent(true);
};
@@ -151,6 +164,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
boolean isUserSentimentNegative)
throws RemoteException {
mINotificationManager = iNotificationManager;
+ mMetricsLogger = Dependency.get(MetricsLogger.class);
mPackageName = pkg;
mNumUniqueChannelsInRow = numUniqueChannelsInRow;
mSbn = sbn;
@@ -183,6 +197,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
bindHeader();
bindPrompt();
bindButtons();
+
+ logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_SHOWN);
}
private void bindHeader() throws RemoteException {
@@ -235,6 +251,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
final int appUidF = mAppUid;
settingsButton.setOnClickListener(
(View view) -> {
+ logBlockingHelperCounter(
+ NotificationCounters.BLOCKING_HELPER_NOTIF_SETTINGS);
mOnSettingsClickListener.onClick(view,
mNumUniqueChannelsInRow > 1 ? null : mSingleNotificationChannel,
appUidF);
@@ -269,6 +287,13 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
}
+ @VisibleForTesting
+ void logBlockingHelperCounter(String counterTag) {
+ if (mIsForBlockingHelper) {
+ mMetricsLogger.count(counterTag, 1);
+ }
+ }
+
private boolean hasImportanceChanged() {
return mSingleNotificationChannel != null && mStartingUserImportance != mChosenImportance;
}
@@ -437,25 +462,15 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
*/
@VisibleForTesting
void closeControls(View v) {
- if (mIsForBlockingHelper) {
- NotificationBlockingHelperManager manager =
- Dependency.get(NotificationBlockingHelperManager.class);
- manager.dismissCurrentBlockingHelper();
-
- // Since this won't get a callback via gutsContainer.closeControls, save the new
- // importance values immediately.
- saveImportance();
- } else {
- int[] parentLoc = new int[2];
- int[] targetLoc = new int[2];
- mGutsContainer.getLocationOnScreen(parentLoc);
- v.getLocationOnScreen(targetLoc);
- final int centerX = v.getWidth() / 2;
- final int centerY = v.getHeight() / 2;
- final int x = targetLoc[0] - parentLoc[0] + centerX;
- final int y = targetLoc[1] - parentLoc[1] + centerY;
- mGutsContainer.closeControls(x, y, true /* save */, false /* force */);
- }
+ int[] parentLoc = new int[2];
+ int[] targetLoc = new int[2];
+ mGutsContainer.getLocationOnScreen(parentLoc);
+ v.getLocationOnScreen(targetLoc);
+ final int centerX = v.getWidth() / 2;
+ final int centerY = v.getHeight() / 2;
+ final int x = targetLoc[0] - parentLoc[0] + centerX;
+ final int y = targetLoc[1] - parentLoc[1] + centerY;
+ mGutsContainer.closeControls(x, y, true /* save */, false /* force */);
}
@Override
@@ -480,6 +495,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
if (save) {
saveImportance();
}
+ logBlockingHelperCounter(mExitReasonCounter);
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
index bf94c1f8a98b..c3b4fdd07bab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
@@ -191,6 +191,7 @@ public class StatusBarWifiView extends FrameLayout implements DarkReceiver,
}
private void updateState(WifiIconState state) {
+ setContentDescription(state.contentDescription);
if (mState.resId != state.resId && state.resId >= 0) {
NeutralGoodDrawable drawable = NeutralGoodDrawable
.create(mLightContext, mDarkContext, state.resId);
@@ -212,6 +213,7 @@ public class StatusBarWifiView extends FrameLayout implements DarkReceiver,
}
private void initViewState() {
+ setContentDescription(mState.contentDescription);
if (mState.resId >= 0) {
NeutralGoodDrawable drawable = NeutralGoodDrawable.create(
mLightContext, mDarkContext, mState.resId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCounters.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCounters.java
new file mode 100644
index 000000000000..9a12e8baef08
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCounters.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 com.android.systemui.statusbar.notification;
+
+/**
+ * Constants for counter tags for Notification-related actions/views.
+ */
+public class NotificationCounters {
+ /** Counter tag for notification dismissal. */
+ public static final String NOTIFICATION_DISMISSED = "notification_dismissed";
+
+ /** Counter tag for when the blocking helper is shown to the user. */
+ public static final String BLOCKING_HELPER_SHOWN = "blocking_helper_shown";
+ /** Counter tag for when the blocking helper is dismissed via a miscellaneous interaction. */
+ public static final String BLOCKING_HELPER_DISMISSED = "blocking_helper_dismissed";
+ /** Counter tag for when the user hits 'stop notifications' in the blocking helper. */
+ public static final String BLOCKING_HELPER_STOP_NOTIFICATIONS =
+ "blocking_helper_stop_notifications";
+ /** Counter tag for when the user hits 'keep showing' in the blocking helper. */
+ public static final String BLOCKING_HELPER_KEEP_SHOWING =
+ "blocking_helper_keep_showing";
+ /**
+ * Counter tag for when the user hits undo in context of the blocking helper - this can happen
+ * multiple times per view.
+ */
+ public static final String BLOCKING_HELPER_UNDO = "blocking_helper_undo";
+ /** Counter tag for when the user hits the notification settings icon in the blocking helper. */
+ public static final String BLOCKING_HELPER_NOTIF_SETTINGS =
+ "blocking_helper_notif_settings";
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
index 7284ee8b39bc..2161655a64c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -14,8 +14,12 @@
package com.android.systemui.statusbar.phone;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.view.View;
+import com.android.systemui.Interpolators;
import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonInterface;
import com.android.systemui.statusbar.policy.KeyButtonDrawable;
@@ -26,6 +30,8 @@ import java.util.ArrayList;
* multiples of the same nav bar icon appearing.
*/
public class ButtonDispatcher {
+ private final static int FADE_DURATION_IN = 150;
+ private final static int FADE_DURATION_OUT = 100;
private final ArrayList<View> mViews = new ArrayList<>();
@@ -36,13 +42,24 @@ public class ButtonDispatcher {
private View.OnLongClickListener mLongClickListener;
private View.OnHoverListener mOnHoverListener;
private Boolean mLongClickable;
- private Integer mAlpha;
+ private Float mAlpha;
private Float mDarkIntensity;
private Integer mVisibility = -1;
private Boolean mDelayTouchFeedback;
private KeyButtonDrawable mImageDrawable;
private View mCurrentView;
private boolean mVertical;
+ private ValueAnimator mFadeAnimator;
+
+ private final ValueAnimator.AnimatorUpdateListener mAlphaListener = animation ->
+ setAlpha((float) animation.getAnimatedValue());
+
+ private final AnimatorListenerAdapter mFadeListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ setVisibility(getAlpha() == 1 ? View.VISIBLE : View.INVISIBLE);
+ }
+ };
public ButtonDispatcher(int id) {
mId = id;
@@ -64,19 +81,22 @@ public class ButtonDispatcher {
if (mAlpha != null) {
view.setAlpha(mAlpha);
}
- if (mDarkIntensity != null) {
- ((ButtonInterface) view).setDarkIntensity(mDarkIntensity);
- }
- if (mVisibility != null) {
+ if (mVisibility != null && mVisibility != -1) {
view.setVisibility(mVisibility);
}
- if (mImageDrawable != null) {
- ((ButtonInterface) view).setImageDrawable(mImageDrawable);
- }
- if (mDelayTouchFeedback != null) {
- ((ButtonInterface) view).setDelayTouchFeedback(mDelayTouchFeedback);
+ if (view instanceof ButtonInterface) {
+ final ButtonInterface button = (ButtonInterface) view;
+ if (mDarkIntensity != null) {
+ button.setDarkIntensity(mDarkIntensity);
+ }
+ if (mImageDrawable != null) {
+ button.setImageDrawable(mImageDrawable);
+ }
+ if (mDelayTouchFeedback != null) {
+ button.setDelayTouchFeedback(mDelayTouchFeedback);
+ }
+ button.setVertical(mVertical);
}
- ((ButtonInterface) view).setVertical(mVertical);
}
public int getId() {
@@ -99,7 +119,9 @@ public class ButtonDispatcher {
mImageDrawable = drawable;
final int N = mViews.size();
for (int i = 0; i < N; i++) {
- ((ButtonInterface) mViews.get(i)).setImageDrawable(mImageDrawable);
+ if (mViews.get(i) instanceof ButtonInterface) {
+ ((ButtonInterface) mViews.get(i)).setImageDrawable(mImageDrawable);
+ }
}
}
@@ -116,11 +138,13 @@ public class ButtonDispatcher {
// This seems to be an instantaneous thing, so not going to persist it.
final int N = mViews.size();
for (int i = 0; i < N; i++) {
- ((ButtonInterface) mViews.get(i)).abortCurrentGesture();
+ if (mViews.get(i) instanceof ButtonInterface) {
+ ((ButtonInterface) mViews.get(i)).abortCurrentGesture();
+ }
}
}
- public void setAlpha(int alpha) {
+ public void setAlpha(float alpha) {
mAlpha = alpha;
final int N = mViews.size();
for (int i = 0; i < N; i++) {
@@ -132,7 +156,9 @@ public class ButtonDispatcher {
mDarkIntensity = darkIntensity;
final int N = mViews.size();
for (int i = 0; i < N; i++) {
- ((ButtonInterface) mViews.get(i)).setDarkIntensity(darkIntensity);
+ if (mViews.get(i) instanceof ButtonInterface) {
+ ((ButtonInterface) mViews.get(i)).setDarkIntensity(darkIntensity);
+ }
}
}
@@ -140,7 +166,9 @@ public class ButtonDispatcher {
mDelayTouchFeedback = delay;
final int N = mViews.size();
for (int i = 0; i < N; i++) {
- ((ButtonInterface) mViews.get(i)).setDelayTouchFeedback(delay);
+ if (mViews.get(i) instanceof ButtonInterface) {
+ ((ButtonInterface) mViews.get(i)).setDelayTouchFeedback(delay);
+ }
}
}
@@ -192,6 +220,19 @@ public class ButtonDispatcher {
}
}
+ public void animateFade(boolean in) {
+ if (mFadeAnimator != null) {
+ mFadeAnimator.cancel();
+ }
+ mFadeAnimator = ValueAnimator.ofFloat(getAlpha(), in ? 1 : 0);
+ mFadeAnimator.setDuration(in? FADE_DURATION_IN : FADE_DURATION_OUT);
+ mFadeAnimator.setInterpolator(in ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT);
+ mFadeAnimator.addListener(mFadeListener);
+ mFadeAnimator.addUpdateListener(mAlphaListener);
+ mFadeAnimator.start();
+ setVisibility(View.VISIBLE);
+ }
+
public ArrayList<View> getViews() {
return mViews;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index 824960ee6f83..46b4078a1801 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -24,6 +24,7 @@ import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;
import com.android.internal.statusbar.StatusBarIcon;
@@ -56,7 +57,14 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da
mIconSize = iconSize;
mColor = DarkIconDispatcher.DEFAULT_ICON_TINT;
+ if (statusIcons instanceof StatusIconContainer) {
+ setShouldRestrictIcons(((StatusIconContainer) statusIcons).isRestrictingIcons());
+ } else {
+ setShouldRestrictIcons(false);
+ }
setLayoutParams(mStatusIcons.getLayoutParams());
+ setPadding(mStatusIcons.getPaddingLeft(),mStatusIcons.getPaddingTop(),
+ mStatusIcons.getPaddingRight(), mStatusIcons.getPaddingBottom());
setOrientation(mStatusIcons.getOrientation());
setGravity(Gravity.CENTER_VERTICAL); // no LL.getGravity()
ViewGroup p = (ViewGroup) mStatusIcons.getParent();
@@ -77,6 +85,7 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da
for (int i = 0; i < getChildCount(); i++) {
StatusIconDisplayable child = (StatusIconDisplayable) getChildAt(i);
child.setStaticDrawableColor(mColor);
+ child.setDecorColor(mColor);
}
}
@@ -189,11 +198,12 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da
}
StatusBarIcon icon = new StatusBarIcon(iconPkg, UserHandle.SYSTEM, iconId, 0, 0, "Demo");
icon.visible = true;
- StatusBarIconView v = new StatusBarIconView(getContext(), null, null);
+ StatusBarIconView v = new StatusBarIconView(getContext(), slot, null, false);
v.setTag(slot);
v.set(icon);
v.setStaticDrawableColor(mColor);
- addView(v, 0, new LinearLayout.LayoutParams(mIconSize, mIconSize));
+ v.setDecorColor(mColor);
+ addView(v, 0, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize));
}
public void addDemoWifiView(WifiIconState state) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 3e01aec85139..f13415103b9d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -54,6 +54,8 @@ public class KeyguardBouncer {
private static final String TAG = "KeyguardBouncer";
static final float ALPHA_EXPANSION_THRESHOLD = 0.95f;
+ private static final float EXPANSION_HIDDEN = 1f;
+ private static final float EXPANSION_VISIBLE = 0f;
protected final Context mContext;
protected final ViewMediatorCallback mCallback;
@@ -71,10 +73,15 @@ public class KeyguardBouncer {
}
};
private final Runnable mRemoveViewRunnable = this::removeView;
+ protected KeyguardHostView mKeyguardView;
+ private final Runnable mResetRunnable = ()-> {
+ if (mKeyguardView != null) {
+ mKeyguardView.reset();
+ }
+ };
private int mStatusBarHeight;
- private float mExpansion;
- protected KeyguardHostView mKeyguardView;
+ private float mExpansion = EXPANSION_HIDDEN;
protected ViewGroup mRoot;
private boolean mShowingSoon;
private int mBouncerPromptReason;
@@ -96,7 +103,7 @@ public class KeyguardBouncer {
}
public void show(boolean resetSecuritySelection) {
- show(resetSecuritySelection, true /* notifyFalsing */);
+ show(resetSecuritySelection, true /* animated */);
}
/**
@@ -120,8 +127,7 @@ public class KeyguardBouncer {
// Later, at the end of the animation, when the bouncer is at the top of the screen,
// onFullyShown() will be called and FalsingManager will stop recording touches.
if (animated) {
- mFalsingManager.onBouncerShown();
- setExpansion(0);
+ setExpansion(EXPANSION_VISIBLE);
}
if (resetSecuritySelection) {
@@ -152,6 +158,7 @@ public class KeyguardBouncer {
mShowingSoon = true;
// Split up the work over multiple frames.
+ DejankUtils.removeCallbacks(mResetRunnable);
DejankUtils.postAfterTraversal(mShowRunnable);
mCallback.onBouncerVisiblityChanged(true /* shown */);
@@ -181,6 +188,7 @@ public class KeyguardBouncer {
mRoot.setVisibility(View.INVISIBLE);
}
mFalsingManager.onBouncerHidden();
+ DejankUtils.postAfterTraversal(mResetRunnable);
}
}
@@ -210,6 +218,9 @@ public class KeyguardBouncer {
mKeyguardView.requestLayout();
}
mShowingSoon = false;
+ if (mExpansion == EXPANSION_VISIBLE) {
+ mKeyguardView.onResume();
+ }
StatsLog.write(StatsLog.KEYGUARD_BOUNCER_STATE_CHANGED,
StatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SHOWN);
}
@@ -303,7 +314,7 @@ public class KeyguardBouncer {
public boolean isShowing() {
return (mShowingSoon || (mRoot != null && mRoot.getVisibility() == View.VISIBLE))
- && mExpansion == 0 && !isAnimatingAway();
+ && mExpansion == EXPANSION_VISIBLE && !isAnimatingAway();
}
/**
@@ -337,10 +348,10 @@ public class KeyguardBouncer {
mKeyguardView.setTranslationY(fraction * mKeyguardView.getHeight());
}
- if (fraction == 0 && oldExpansion != 0) {
+ if (fraction == EXPANSION_VISIBLE && oldExpansion != EXPANSION_VISIBLE) {
onFullyShown();
mExpansionCallback.onFullyShown();
- } else if (fraction == 1 && oldExpansion != 0) {
+ } else if (fraction == EXPANSION_HIDDEN && oldExpansion != EXPANSION_HIDDEN) {
onFullyHidden();
mExpansionCallback.onFullyHidden();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
index 759a0d173cdd..76ddca47d33e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
@@ -23,7 +23,9 @@ import com.android.keyguard.KeyguardHostView.OnDismissAction;
/** Executes actions that require the screen to be unlocked. */
public interface KeyguardDismissHandler {
- /** Executes an action that requres the screen to be unlocked. */
- void dismissKeyguardThenExecute(
- OnDismissAction action, @Nullable Runnable cancelAction, boolean afterKeyguardGone);
+ /**
+ * Executes an action that requres the screen to be unlocked, showing the keyguard if
+ * necessary. Does not close the notification shade (in case it was open).
+ */
+ void executeWhenUnlocked(OnDismissAction action);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
index c38b0b63190d..d67669289915 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
@@ -40,14 +40,13 @@ public class KeyguardDismissUtil implements KeyguardDismissHandler {
* <p>Must be called after {@link #setDismissHandler}.
*/
@Override
- public void dismissKeyguardThenExecute(
- OnDismissAction action, Runnable cancelAction, boolean afterKeyguardGone) {
+ public void executeWhenUnlocked(OnDismissAction action) {
KeyguardDismissHandler dismissHandler = mDismissHandler;
if (dismissHandler == null) {
Log.wtf(TAG, "KeyguardDismissHandler not set.");
action.onDismiss();
return;
}
- dismissHandler.dismissKeyguardThenExecute(action, cancelAction, afterKeyguardGone);
+ dismissHandler.executeWhenUnlocked(action);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 264f5749fa73..4b66ee5aa68e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -55,6 +55,7 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange
private final UnlockMethodCache mUnlockMethodCache;
private AccessibilityController mAccessibilityController;
private boolean mHasFingerPrintIcon;
+ private boolean mHasFaceUnlockIcon;
private int mDensity;
private final Runnable mDrawOffTimeout = () -> update(true /* forceUpdate */);
@@ -130,6 +131,7 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange
}
int state = getState();
boolean anyFingerprintIcon = state == STATE_FINGERPRINT || state == STATE_FINGERPRINT_ERROR;
+ mHasFaceUnlockIcon = state == STATE_FACE_UNLOCK;
boolean useAdditionalPadding = anyFingerprintIcon;
boolean trustHidden = anyFingerprintIcon;
if (state != mLastState || mDeviceInteractive != mLastDeviceInteractive
@@ -179,6 +181,11 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange
setRestingAlpha(
anyFingerprintIcon ? 1f : KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT);
setImageDrawable(icon, false);
+ if (mHasFaceUnlockIcon) {
+ announceForAccessibility(getContext().getString(
+ R.string.accessibility_scanning_face));
+ }
+
mHasFingerPrintIcon = anyFingerprintIcon;
if (animation != null && isAnim) {
animation.forceAnimationOnUI();
@@ -228,6 +235,11 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange
info.addAction(unlock);
info.setHintText(getContext().getString(
R.string.accessibility_waiting_for_fingerprint));
+ } else if (mHasFaceUnlockIcon){
+ //Avoid 'button' to be spoken for scanning face
+ info.setClassName(LockIcon.class.getName());
+ info.setContentDescription(getContext().getString(
+ R.string.accessibility_scanning_face));
}
}
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 91cf8f086905..4885c2f796d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -168,10 +168,10 @@ public class NavigationBarInflaterView extends FrameLayout
}
}
- public void setButtonDispatchers(SparseArray<ButtonDispatcher> buttonDisatchers) {
- mButtonDispatchers = buttonDisatchers;
- for (int i = 0; i < buttonDisatchers.size(); i++) {
- initiallyFill(buttonDisatchers.valueAt(i));
+ public void setButtonDispatchers(SparseArray<ButtonDispatcher> buttonDispatchers) {
+ mButtonDispatchers = buttonDispatchers;
+ for (int i = 0; i < buttonDispatchers.size(); i++) {
+ initiallyFill(buttonDispatchers.valueAt(i));
}
}
@@ -220,7 +220,8 @@ public class NavigationBarInflaterView extends FrameLayout
// and will only happen once.
if (parent.getChildAt(i).getId() == buttonDispatcher.getId()) {
buttonDispatcher.addView(parent.getChildAt(i));
- } else if (parent.getChildAt(i) instanceof ViewGroup) {
+ }
+ if (parent.getChildAt(i) instanceof ViewGroup) {
addAll(buttonDispatcher, (ViewGroup) parent.getChildAt(i));
}
}
@@ -411,7 +412,8 @@ public class NavigationBarInflaterView extends FrameLayout
final int indexOfKey = mButtonDispatchers.indexOfKey(v.getId());
if (indexOfKey >= 0) {
mButtonDispatchers.valueAt(indexOfKey).addView(v);
- } else if (v instanceof ViewGroup) {
+ }
+ if (v instanceof ViewGroup) {
final ViewGroup viewGroup = (ViewGroup)v;
final int N = viewGroup.getChildCount();
for (int i = 0; i < N; i++) {
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 6dbe9f89dcde..6cc96da96e45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -260,6 +260,8 @@ 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));
+ mButtonDispatchers.put(R.id.menu_container,
+ new ButtonDispatcher(R.id.menu_container));
mDeadZone = new DeadZone(this);
}
@@ -368,6 +370,10 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
return mButtonDispatchers.get(R.id.rotate_suggestion);
}
+ public ButtonDispatcher getMenuContainer() {
+ return mButtonDispatchers.get(R.id.menu_container);
+ }
+
public SparseArray<ButtonDispatcher> getButtonDispatchers() {
return mButtonDispatchers;
}
@@ -796,6 +802,10 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
public boolean isRotateButtonVisible() { return mShowRotateButton; }
+ public void setMenuContainerVisibility(boolean visible) {
+ getMenuContainer().animateFade(visible);
+ }
+
@Override
public void onFinishInflate() {
mNavigationInflaterView = (NavigationBarInflaterView) findViewById(
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 b650944403cb..8bb73da564b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -199,6 +199,7 @@ public class NotificationPanelView extends PanelView implements
private ValueAnimator mQsSizeChangeAnimator;
private boolean mShowEmptyShadeView;
+ private boolean mShowDndView;
private boolean mQsScrimEnabled = true;
private boolean mLastAnnouncementWasQuickSettings;
@@ -1599,8 +1600,8 @@ public class NotificationPanelView extends PanelView implements
// When only empty shade view is visible in QS collapsed state, simulate that we would have
// it in expanded QS state as well so we don't run into troubles when fading the view in/out
// and expanding/collapsing the whole panel from/to quick settings.
- if (mNotificationStackScroller.getNotGoneChildCount() == 0
- && mShowEmptyShadeView) {
+ if ((mNotificationStackScroller.getNotGoneChildCount() == 0
+ && mShowEmptyShadeView) || mShowDndView) {
notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight();
}
int maxQsHeight = mQsMaxExpansionHeight;
@@ -2243,13 +2244,17 @@ public class NotificationPanelView extends PanelView implements
return mDozing;
}
+ public void showDndView(boolean dndViewVisible) {
+ mShowDndView = dndViewVisible;
+ mNotificationStackScroller.updateDndView(mShowDndView && !mQsExpanded);
+ }
+
public void showEmptyShadeView(boolean emptyShadeViewVisible) {
mShowEmptyShadeView = emptyShadeViewVisible;
updateEmptyShadeView();
}
private void updateEmptyShadeView() {
-
// Hide "No notifications" in QS.
mNotificationStackScroller.updateEmptyShadeView(mShowEmptyShadeView && !mQsExpanded);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index 6b0ac948a036..1a1839d6e457 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -401,6 +401,10 @@ public class QuickStepController implements GestureHelper {
mDarkTrackColor = mContext.getColor(R.color.quick_step_track_background_dark);
mTrackAnimator.setFloatValues(0, 1);
mTrackAnimator.start();
+
+ // Hide menu buttons on nav bar until quick scrub has ended
+ mNavigationBarView.setMenuContainerVisibility(false /* visible */);
+
try {
mOverviewEventSender.getProxy().onQuickScrubStart();
if (DEBUG_OVERVIEW_PROXY) {
@@ -416,6 +420,10 @@ public class QuickStepController implements GestureHelper {
private void endQuickScrub(boolean animate) {
if (mQuickScrubActive || mDragScrubActive) {
animateEnd();
+
+ // Restore the nav bar menu buttons visibility
+ mNavigationBarView.setMenuContainerVisibility(true /* visible */);
+
if (mQuickScrubActive) {
try {
mOverviewEventSender.getProxy().onQuickScrubEnd();
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 d6b45d69839a..ae93d986ea36 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -92,7 +92,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
/**
* Default alpha value for most scrims.
*/
- public static final float GRADIENT_SCRIM_ALPHA = 0.70f;
+ public static final float GRADIENT_SCRIM_ALPHA = 0.45f;
/**
* A scrim varies its opacity based on a busyness factor, for example
* how many notifications are currently visible.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index bbdaa9993bec..1c5df5801f42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -60,7 +60,7 @@ public enum ScrimState {
@Override
public float getBehindAlpha(float busynessFactor) {
return MathUtils.map(0 /* start */, 1 /* stop */,
- ScrimController.GRADIENT_SCRIM_ALPHA, ScrimController.GRADIENT_SCRIM_ALPHA_BUSY,
+ mScrimBehindAlphaKeyguard, ScrimController.GRADIENT_SCRIM_ALPHA_BUSY,
busynessFactor);
}
},
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 1d64088099ec..5f0759974709 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -20,10 +20,13 @@ import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.windowStateToString;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
+import static android.provider.Settings.Global.ZEN_MODE_OFF;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
+import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_LEFT;
+import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_INVALID;
import static com.android.systemui.statusbar.NotificationLockscreenUserManager
.NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION;
import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
@@ -166,6 +169,7 @@ import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
import com.android.systemui.qs.QSFragment;
@@ -178,6 +182,7 @@ import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
import com.android.systemui.recents.events.activity.UndockingTaskEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.stackdivider.WindowManagerProxy;
import com.android.systemui.statusbar.ActivatableNotificationView;
@@ -185,6 +190,7 @@ import com.android.systemui.statusbar.AppOpsListener;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CrossFadeHelper;
+import com.android.systemui.statusbar.DndSuppressingNotificationsView;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
@@ -207,14 +213,12 @@ import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.ScrimView;
-import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.notification.AboveShelfObserver;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
-import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
@@ -412,7 +416,7 @@ public class StatusBar extends SystemUI implements DemoMode,
protected NotificationViewHierarchyManager mViewHierarchyManager;
protected AppOpsListener mAppOpsListener;
protected KeyguardViewMediator mKeyguardViewMediator;
- private ZenModeController mZenController;
+ protected ZenModeController mZenController;
/**
* Helper that is responsible for showing the right toast when a disallowed activity operation
@@ -877,6 +881,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mVisualStabilityManager.setVisibilityLocationProvider(mStackScroller);
inflateEmptyShadeView();
+ inflateDndView();
inflateFooterView();
mBackdrop = mStatusBarWindow.findViewById(R.id.backdrop);
@@ -1144,6 +1149,7 @@ public class StatusBar extends SystemUI implements DemoMode,
protected void reevaluateStyles() {
inflateFooterView();
updateFooter();
+ inflateDndView();
inflateEmptyShadeView();
updateEmptyShadeView();
}
@@ -1165,6 +1171,19 @@ public class StatusBar extends SystemUI implements DemoMode,
mStackScroller.setEmptyShadeView(mEmptyShadeView);
}
+ private void inflateDndView() {
+ if (mStackScroller == null) {
+ return;
+ }
+ mDndView = (DndSuppressingNotificationsView) LayoutInflater.from(mContext).inflate(
+ R.layout.status_bar_dnd_suppressing_notifications, mStackScroller, false);
+ mDndView.setOnContentClickListener(v -> {
+ Intent intent = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+ startActivity(intent, true, true, Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ });
+ mStackScroller.setDndView(mDndView);
+ }
+
private void inflateFooterView() {
if (mStackScroller == null) {
return;
@@ -1307,8 +1326,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
mLightBarController.setFingerprintUnlockController(mFingerprintUnlockController);
- Dependency.get(KeyguardDismissUtil.class).setDismissHandler(
- this::dismissKeyguardThenExecute);
+ Dependency.get(KeyguardDismissUtil.class).setDismissHandler(this::executeWhenUnlocked);
Trace.endSection();
}
@@ -1339,8 +1357,15 @@ public class StatusBar extends SystemUI implements DemoMode,
}
int dockSide = WindowManagerProxy.getInstance().getDockSide();
if (dockSide == WindowManager.DOCKED_INVALID) {
- return mRecents.splitPrimaryTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
- ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null, metricsDockAction);
+ final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition();
+ if (navbarPos == NAV_BAR_POS_INVALID) {
+ return false;
+ }
+ int createMode = navbarPos == NAV_BAR_POS_LEFT
+ ? ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT
+ : ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
+ return mRecents.splitPrimaryTask(NavigationBarGestureHelper.DRAG_MODE_NONE, createMode,
+ null, metricsDockAction);
} else {
Divider divider = getComponent(Divider.class);
if (divider != null && divider.isMinimized() && !divider.isHomeStackResizable()) {
@@ -1452,9 +1477,11 @@ public class StatusBar extends SystemUI implements DemoMode,
@VisibleForTesting
protected void updateFooter() {
boolean showFooterView = mState != StatusBarState.KEYGUARD
+ && !areNotificationsHidden()
&& mEntryManager.getNotificationData().getActiveNotifications().size() != 0
&& !mRemoteInputManager.getController().isRemoteInputActive();
boolean showDismissView = mClearAllEnabled && mState != StatusBarState.KEYGUARD
+ && !areNotificationsHidden()
&& hasActiveClearableNotifications();
mStackScroller.updateFooterView(showFooterView, showDismissView);
@@ -1477,10 +1504,13 @@ public class StatusBar extends SystemUI implements DemoMode,
return false;
}
- private void updateEmptyShadeView() {
- boolean showEmptyShadeView =
- mState != StatusBarState.KEYGUARD &&
- mEntryManager.getNotificationData().getActiveNotifications().size() == 0;
+ @VisibleForTesting
+ protected void updateEmptyShadeView() {
+ boolean showDndView = mState != StatusBarState.KEYGUARD && areNotificationsHidden();
+ boolean showEmptyShadeView = !showDndView
+ && mState != StatusBarState.KEYGUARD
+ && mEntryManager.getNotificationData().getActiveNotifications().size() == 0;
+ mNotificationPanel.showDndView(showDndView);
mNotificationPanel.showEmptyShadeView(showEmptyShadeView);
}
@@ -1896,6 +1926,13 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
+ if (!panelsEnabled()) {
+ if (DEBUG) {
+ Log.d(TAG, "No peeking: disabled panel : " + sbn.getKey());
+ }
+ return false;
+ }
+
if (sbn.getNotification().fullScreenIntent != null) {
if (mAccessibilityManager.isTouchExplorationEnabled()) {
if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
@@ -3050,6 +3087,13 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
+ private void executeWhenUnlocked(OnDismissAction action) {
+ if (mStatusBarKeyguardViewManager.isShowing()) {
+ mLeaveOpenOnKeyguardHide = true;
+ }
+ dismissKeyguardThenExecute(action, null /* cancelAction */, false /* afterKeyguardGone */);
+ }
+
protected void dismissKeyguardThenExecute(OnDismissAction action, boolean afterKeyguardGone) {
dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone);
}
@@ -4973,6 +5017,7 @@ public class StatusBar extends SystemUI implements DemoMode,
protected NotificationShelf mNotificationShelf;
protected FooterView mFooterView;
protected EmptyShadeView mEmptyShadeView;
+ protected DndSuppressingNotificationsView mDndView;
protected AssistManager mAssistManager;
@@ -5457,6 +5502,11 @@ public class StatusBar extends SystemUI implements DemoMode,
mStackScroller.getChildCount() - offsetFromEnd++);
}
+ if (mDndView != null) {
+ mStackScroller.changeViewPosition(mDndView,
+ mStackScroller.getChildCount() - offsetFromEnd++);
+ }
+
mStackScroller.changeViewPosition(mEmptyShadeView,
mStackScroller.getChildCount() - offsetFromEnd++);
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 c97c8ebd0545..8398879b9c07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -73,19 +73,23 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout {
public StatusIconContainer(Context context, AttributeSet attrs) {
super(context, attrs);
+ initDimens();
+ setWillNotDraw(!DEBUG_OVERFLOW);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- setWillNotDraw(!DEBUG_OVERFLOW);
- initDimens();
}
public void setShouldRestrictIcons(boolean should) {
mShouldRestrictIcons = should;
}
+ public boolean isRestrictingIcons() {
+ return mShouldRestrictIcons;
+ }
+
private void initDimens() {
// This is the same value that StatusBarIconView uses
mIconDotFrameWidth = getResources().getDimensionPixelSize(
@@ -209,8 +213,8 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout {
int childCount = getChildCount();
// Underflow === don't show content until that index
int firstUnderflowIndex = -1;
- if (DEBUG) android.util.Log.d(TAG, "calculateIconTransitions: start=" + translationX
- + " width=" + width);
+ if (DEBUG) android.util.Log.d(TAG, "calculateIconTranslations: start=" + translationX
+ + " width=" + width + " underflow=" + mNeedsUnderflow);
// Collect all of the states which want to be visible
for (int i = childCount - 1; i >= 0; i--) {
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 b4fa2e8b16f8..351868dd8b7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -183,8 +183,7 @@ public class SmartReplyView extends ViewGroup {
};
b.setOnClickListener(view -> {
- mKeyguardDismissUtil.dismissKeyguardThenExecute(
- action, null /* cancelAction */, false /* afterKeyguardGone */);
+ mKeyguardDismissUtil.executeWhenUnlocked(action);
});
b.setAccessibilityDelegate(new AccessibilityDelegate() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 5275e27a2c5a..eeaa6cb58681 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -81,6 +81,7 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.ActivatableNotificationView;
+import com.android.systemui.statusbar.DndSuppressingNotificationsView;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
@@ -236,6 +237,7 @@ public class NotificationStackScrollLayout extends ViewGroup
protected boolean mScrollingEnabled;
protected FooterView mFooterView;
protected EmptyShadeView mEmptyShadeView;
+ protected DndSuppressingNotificationsView mDndView;
private boolean mDismissAllInProgress;
private boolean mFadeNotificationsOnDismiss;
@@ -1006,7 +1008,8 @@ public class NotificationStackScrollLayout extends ViewGroup
private float getAppearEndPosition() {
int appearPosition;
int notGoneChildCount = getNotGoneChildCount();
- if (mEmptyShadeView.getVisibility() == GONE && notGoneChildCount != 0) {
+ if ((mEmptyShadeView.getVisibility() == GONE && mDndView.getVisibility() == GONE)
+ && notGoneChildCount != 0) {
if (isHeadsUpTransition()
|| (mHeadsUpManager.hasPinnedHeadsUp() && !mAmbientState.isDark())) {
appearPosition = getTopHeadsUpPinnedHeight();
@@ -1016,6 +1019,8 @@ public class NotificationStackScrollLayout extends ViewGroup
appearPosition += mShelf.getIntrinsicHeight();
}
}
+ } else if (mEmptyShadeView.getVisibility() == GONE) {
+ appearPosition = mDndView.getHeight();
} else {
appearPosition = mEmptyShadeView.getHeight();
}
@@ -2608,19 +2613,6 @@ public class NotificationStackScrollLayout extends ViewGroup
return mShelf.getVisibility() == GONE ? 0 : mShelf.getIntrinsicHeight();
}
- public int getFirstChildIntrinsicHeight() {
- final ExpandableView firstChild = getFirstChildNotGone();
- int firstChildMinHeight = firstChild != null
- ? firstChild.getIntrinsicHeight()
- : mEmptyShadeView != null
- ? mEmptyShadeView.getIntrinsicHeight()
- : mCollapsedSize;
- if (mOwnScrollY > 0) {
- firstChildMinHeight = Math.max(firstChildMinHeight - mOwnScrollY, mCollapsedSize);
- }
- return firstChildMinHeight;
- }
-
public float getTopPaddingOverflow() {
return mTopPaddingOverflow;
}
@@ -3918,6 +3910,7 @@ public class NotificationStackScrollLayout extends ViewGroup
final int textColor = Utils.getColorAttr(context, R.attr.wallpaperTextColor);
mFooterView.setTextColor(textColor);
mEmptyShadeView.setTextColor(textColor);
+ mDndView.setColor(textColor);
}
public void goToFullShade(long delay) {
@@ -3925,6 +3918,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mFooterView.setInvisible();
}
mEmptyShadeView.setInvisible();
+ mDndView.setInvisible();
mGoToFullShadeNeedsAnimation = true;
mGoToFullShadeDelay = delay;
mNeedsAnimation = true;
@@ -4076,25 +4070,39 @@ public class NotificationStackScrollLayout extends ViewGroup
int newVisibility = visible ? VISIBLE : GONE;
boolean changedVisibility = oldVisibility != newVisibility;
- if (changedVisibility || newVisibility != GONE) {
+ if (changedVisibility) {
if (newVisibility != GONE) {
- int oldText = mEmptyShadeView.getTextResource();
- int newText;
- if (mStatusBar.areNotificationsHidden()) {
- newText = R.string.dnd_suppressing_shade_text;
- } else {
- newText = R.string.empty_shade_text;
- }
- if (changedVisibility || !Objects.equals(oldText, newText)) {
- mEmptyShadeView.setText(newText);
- showFooterView(mEmptyShadeView);
- }
+ showFooterView(mEmptyShadeView);
} else {
hideFooterView(mEmptyShadeView, true);
}
}
}
+ public void setDndView(DndSuppressingNotificationsView dndView) {
+ int index = -1;
+ if (mDndView != null) {
+ index = indexOfChild(mDndView);
+ removeView(mDndView);
+ }
+ mDndView = dndView;
+ addView(mDndView, index);
+ }
+
+ public void updateDndView(boolean visible) {
+ int oldVisibility = mDndView.willBeGone() ? GONE : mDndView.getVisibility();
+ int newVisibility = visible ? VISIBLE : GONE;
+
+ boolean changedVisibility = oldVisibility != newVisibility;
+ if (changedVisibility) {
+ if (newVisibility != GONE) {
+ showFooterView(mDndView);
+ } else {
+ hideFooterView(mDndView, true);
+ }
+ }
+ }
+
public void updateFooterView(boolean visible, boolean showDismissView) {
if (mFooterView == null) {
return;
@@ -4119,10 +4127,16 @@ public class NotificationStackScrollLayout extends ViewGroup
} else {
footerView.setInvisible();
}
- footerView.setVisibility(VISIBLE);
- footerView.setWillBeGone(false);
- updateContentHeight();
- notifyHeightChangeListener(footerView);
+ Runnable onShowFinishRunnable = new Runnable() {
+ @Override
+ public void run() {
+ footerView.setVisibility(VISIBLE);
+ footerView.setWillBeGone(false);
+ updateContentHeight();
+ notifyHeightChangeListener(footerView);
+ }
+ };
+ footerView.performVisibilityAnimation(true, onShowFinishRunnable);
}
private void hideFooterView(StackScrollerDecorView footerView, boolean isButtonVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/DumpTruck.java b/packages/SystemUI/src/com/android/systemui/util/leak/DumpTruck.java
new file mode 100644
index 000000000000..2995eba2b8a7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/DumpTruck.java
@@ -0,0 +1,175 @@
+/*
+ * 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 com.android.systemui.util.leak;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.support.v4.content.FileProvider;
+import android.util.Log;
+
+import com.android.systemui.Dependency;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * Utility class for dumping, compressing, sending, and serving heap dump files.
+ *
+ * <p>Unlike the Internet, this IS a big truck you can dump something on.
+ */
+public class DumpTruck {
+ private static final String FILEPROVIDER_AUTHORITY = "com.android.systemui.fileprovider";
+ private static final String FILEPROVIDER_PATH = "leak";
+
+ private static final String TAG = "DumpTruck";
+ private static final int BUFSIZ = 512 * 1024; // 512K
+
+ private final Context context;
+ private Uri hprofUri;
+ final StringBuilder body = new StringBuilder();
+
+ public DumpTruck(Context context) {
+ this.context = context;
+ }
+
+ /**
+ * Capture memory for the given processes and zip them up for sharing.
+ *
+ * @param pids
+ * @return this, for chaining
+ */
+ public DumpTruck captureHeaps(int[] pids) {
+ final GarbageMonitor gm = Dependency.get(GarbageMonitor.class);
+
+ final File dumpDir = new File(context.getCacheDir(), FILEPROVIDER_PATH);
+ dumpDir.mkdirs();
+ hprofUri = null;
+
+ body.setLength(0);
+ body.append("Build: ").append(Build.DISPLAY).append("\n\nProcesses:\n");
+
+ final ArrayList<String> paths = new ArrayList<String>();
+ final int myPid = android.os.Process.myPid();
+
+ final int[] pids_copy = Arrays.copyOf(pids, pids.length);
+ for (int pid : pids_copy) {
+ body.append(" pid ").append(pid);
+ if (gm != null) {
+ GarbageMonitor.ProcessMemInfo info = gm.getMemInfo(pid);
+ if (info != null) {
+ body.append(":")
+ .append(" up=")
+ .append(info.getUptime())
+ .append(" pss=")
+ .append(info.currentPss)
+ .append(" uss=")
+ .append(info.currentUss);
+ }
+ }
+ if (pid == myPid) {
+ final String path =
+ new File(dumpDir, String.format("heap-%d.ahprof", pid)).getPath();
+ Log.v(TAG, "Dumping memory info for process " + pid + " to " + path);
+ try {
+ android.os.Debug.dumpHprofData(path); // will block
+ paths.add(path);
+ body.append(" (hprof attached)");
+ } catch (IOException e) {
+ Log.e(TAG, "error dumping memory:", e);
+ body.append("\n** Could not dump heap: \n").append(e.toString()).append("\n");
+ }
+ }
+ body.append("\n");
+ }
+
+ try {
+ final String zipfile =
+ new File(dumpDir, String.format("hprof-%d.zip", System.currentTimeMillis()))
+ .getCanonicalPath();
+ if (DumpTruck.zipUp(zipfile, paths)) {
+ final File pathFile = new File(zipfile);
+ hprofUri = FileProvider.getUriForFile(context, FILEPROVIDER_AUTHORITY, pathFile);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "unable to zip up heapdumps", e);
+ body.append("\n** Could not zip up files: \n").append(e.toString()).append("\n");
+ }
+
+ return this;
+ }
+
+ /**
+ * Get the Uri of the current heap dump. Be sure to call captureHeaps first.
+ *
+ * @return Uri to the dump served by the SystemUI file provider
+ */
+ public Uri getDumpUri() {
+ return hprofUri;
+ }
+
+ /**
+ * Get an ACTION_SEND intent suitable for startActivity() or attaching to a Notification.
+ *
+ * @return share intent
+ */
+ public Intent createShareIntent() {
+ Intent shareIntent = new Intent(Intent.ACTION_SEND);
+ shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ shareIntent.putExtra(Intent.EXTRA_SUBJECT, "SystemUI memory dump");
+
+ shareIntent.putExtra(Intent.EXTRA_TEXT, body.toString());
+
+ if (hprofUri != null) {
+ shareIntent.setType("application/zip");
+ shareIntent.putExtra(Intent.EXTRA_STREAM, hprofUri);
+ }
+ return shareIntent;
+ }
+
+ private static boolean zipUp(String zipfilePath, ArrayList<String> paths) {
+ try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipfilePath))) {
+ final byte[] buf = new byte[BUFSIZ];
+
+ for (String filename : paths) {
+ try (InputStream is = new BufferedInputStream(new FileInputStream(filename))) {
+ ZipEntry entry = new ZipEntry(filename);
+ zos.putNextEntry(entry);
+ int len;
+ while (0 < (len = is.read(buf, 0, BUFSIZ))) {
+ zos.write(buf, 0, len);
+ }
+ zos.closeEntry();
+ }
+ }
+ return true;
+ } catch (IOException e) {
+ Log.e(TAG, "error zipping up profile data", e);
+ }
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
index 021f9c4f438b..b2cc2694916e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
@@ -16,88 +16,469 @@
package com.android.systemui.util.leak;
+import static com.android.internal.logging.MetricsLogger.VIEW_UNKNOWN;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Build;
+import android.os.Debug;
import android.os.Handler;
import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
import android.os.SystemProperties;
import android.provider.Settings;
-import android.support.annotation.VisibleForTesting;
+import android.service.quicksettings.Tile;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.util.LongSparseArray;
import com.android.systemui.Dependency;
+import com.android.systemui.R;
import com.android.systemui.SystemUI;
+import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+
+import java.util.ArrayList;
public class GarbageMonitor {
+ private static final boolean LEAK_REPORTING_ENABLED =
+ Build.IS_DEBUGGABLE
+ && SystemProperties.getBoolean("debug.enable_leak_reporting", false);
+ private static final String FORCE_ENABLE_LEAK_REPORTING = "sysui_force_enable_leak_reporting";
+
+ private static final boolean HEAP_TRACKING_ENABLED = Build.IS_DEBUGGABLE;
+ private static final boolean ENABLE_AM_HEAP_LIMIT = true; // use ActivityManager.setHeapLimit
private static final String TAG = "GarbageMonitor";
- private static final long GARBAGE_INSPECTION_INTERVAL = 5 * 60 * 1000; // 5min
+ private static final long GARBAGE_INSPECTION_INTERVAL =
+ 15 * DateUtils.MINUTE_IN_MILLIS; // 15 min
+ private static final long HEAP_TRACK_INTERVAL = 1 * DateUtils.MINUTE_IN_MILLIS; // 1 min
+
+ private static final int DO_GARBAGE_INSPECTION = 1000;
+ private static final int DO_HEAP_TRACK = 3000;
+
private static final int GARBAGE_ALLOWANCE = 5;
private final Handler mHandler;
private final TrackedGarbage mTrackedGarbage;
private final LeakReporter mLeakReporter;
+ private final Context mContext;
+ private final ActivityManager mAm;
+ private MemoryTile mQSTile;
+ private DumpTruck mDumpTruck;
+
+ private final LongSparseArray<ProcessMemInfo> mData = new LongSparseArray<>();
+ private final ArrayList<Long> mPids = new ArrayList<>();
+ private int[] mPidsArray = new int[1];
- public GarbageMonitor(Looper bgLooper, LeakDetector leakDetector,
+ private long mHeapLimit;
+
+ public GarbageMonitor(
+ Context context,
+ Looper bgLooper,
+ LeakDetector leakDetector,
LeakReporter leakReporter) {
- mHandler = bgLooper != null ? new Handler(bgLooper): null;
+ mContext = context.getApplicationContext();
+ mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+
+ mHandler = new BackgroundHeapCheckHandler(bgLooper);
+
mTrackedGarbage = leakDetector.getTrackedGarbage();
mLeakReporter = leakReporter;
+
+ mDumpTruck = new DumpTruck(mContext);
+
+ if (ENABLE_AM_HEAP_LIMIT) {
+ mHeapLimit = mContext.getResources().getInteger(R.integer.watch_heap_limit);
+ }
}
- public void start() {
+ public void startLeakMonitor() {
if (mTrackedGarbage == null) {
return;
}
- scheduleInspectGarbage(this::inspectGarbage);
+ mHandler.sendEmptyMessage(DO_GARBAGE_INSPECTION);
}
- @VisibleForTesting
- void scheduleInspectGarbage(Runnable runnable) {
- mHandler.postDelayed(runnable, GARBAGE_INSPECTION_INTERVAL);
+ public void startHeapTracking() {
+ startTrackingProcess(
+ android.os.Process.myPid(), mContext.getPackageName(), System.currentTimeMillis());
+ mHandler.sendEmptyMessage(DO_HEAP_TRACK);
}
- private void inspectGarbage() {
+ private boolean gcAndCheckGarbage() {
if (mTrackedGarbage.countOldGarbage() > GARBAGE_ALLOWANCE) {
Runtime.getRuntime().gc();
-
- // Allow some time to for ReferenceQueue to catch up.
- scheduleReinspectGarbage(this::reinspectGarbageAfterGc);
+ return true;
}
- scheduleInspectGarbage(this::inspectGarbage);
- }
-
- @VisibleForTesting
- void scheduleReinspectGarbage(Runnable runnable) {
- mHandler.postDelayed(runnable, (long) 100);
+ return false;
}
- private void reinspectGarbageAfterGc() {
+ void reinspectGarbageAfterGc() {
int count = mTrackedGarbage.countOldGarbage();
if (count > GARBAGE_ALLOWANCE) {
mLeakReporter.dumpLeak(count);
}
}
- public static class Service extends SystemUI {
+ public ProcessMemInfo getMemInfo(int pid) {
+ return mData.get(pid);
+ }
+
+ public int[] getTrackedProcesses() {
+ return mPidsArray;
+ }
+
+ public void startTrackingProcess(long pid, String name, long start) {
+ synchronized (mPids) {
+ if (mPids.contains(pid)) return;
+
+ mPids.add(pid);
+ updatePidsArrayL();
+
+ mData.put(pid, new ProcessMemInfo(pid, name, start));
+ }
+ }
+
+ private void updatePidsArrayL() {
+ final int N = mPids.size();
+ mPidsArray = new int[N];
+ StringBuffer sb = new StringBuffer("Now tracking processes: ");
+ for (int i = 0; i < N; i++) {
+ final int p = mPids.get(i).intValue();
+ mPidsArray[i] = p;
+ sb.append(p);
+ sb.append(" ");
+ }
+ Log.v(TAG, sb.toString());
+ }
+
+ private void update() {
+ synchronized (mPids) {
+ Debug.MemoryInfo[] dinfos = mAm.getProcessMemoryInfo(mPidsArray);
+ for (int i = 0; i < dinfos.length; i++) {
+ Debug.MemoryInfo dinfo = dinfos[i];
+ if (i > mPids.size()) {
+ Log.e(TAG, "update: unknown process info received: " + dinfo);
+ break;
+ }
+ final long pid = mPids.get(i).intValue();
+ final ProcessMemInfo info = mData.get(pid);
+ info.head = (info.head + 1) % info.pss.length;
+ info.pss[info.head] = info.currentPss = dinfo.getTotalPss();
+ info.uss[info.head] = info.currentUss = dinfo.getTotalPrivateDirty();
+ if (info.currentPss > info.max) info.max = info.currentPss;
+ if (info.currentUss > info.max) info.max = info.currentUss;
+ if (info.currentPss == 0) {
+ Log.v(TAG, "update: pid " + pid + " has pss=0, it probably died");
+ mData.remove(pid);
+ }
+ }
+ for (int i = mPids.size() - 1; i >= 0; i--) {
+ final long pid = mPids.get(i).intValue();
+ if (mData.get(pid) == null) {
+ mPids.remove(i);
+ updatePidsArrayL();
+ }
+ }
+ }
+ if (mQSTile != null) mQSTile.update();
+ }
+
+ private void setTile(MemoryTile tile) {
+ mQSTile = tile;
+ if (tile != null) tile.update();
+ }
+
+ private static String formatBytes(long b) {
+ String[] SUFFIXES = {"B", "K", "M", "G", "T"};
+ int i;
+ for (i = 0; i < SUFFIXES.length; i++) {
+ if (b < 1024) break;
+ b /= 1024;
+ }
+ return b + SUFFIXES[i];
+ }
+
+ private void dumpHprofAndShare() {
+ final Intent share = mDumpTruck.captureHeaps(getTrackedProcesses()).createShareIntent();
+ mContext.startActivity(share);
+ }
+
+ private static class MemoryIconDrawable extends Drawable {
+ long pss, limit;
+ final Drawable baseIcon;
+ final Paint paint = new Paint();
+ final float dp;
+
+ MemoryIconDrawable(Context context) {
+ baseIcon = context.getDrawable(R.drawable.ic_memory).mutate();
+ dp = context.getResources().getDisplayMetrics().density;
+ paint.setColor(QSTileImpl.getColorForState(context, Tile.STATE_ACTIVE));
+ }
+
+ public void setPss(long pss) {
+ if (pss != this.pss) {
+ this.pss = pss;
+ invalidateSelf();
+ }
+ }
+
+ public void setLimit(long limit) {
+ if (limit != this.limit) {
+ this.limit = limit;
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ baseIcon.draw(canvas);
+
+ if (limit > 0 && pss > 0) {
+ float frac = Math.min(1f, (float) pss / limit);
+
+ final Rect bounds = getBounds();
+ canvas.translate(bounds.left + 8 * dp, bounds.top + 5 * dp);
+ //android:pathData="M16.0,5.0l-8.0,0.0l0.0,14.0l8.0,0.0z"
+ canvas.drawRect(0, 14 * dp * (1 - frac), 8 * dp + 1, 14 * dp + 1, paint);
+ }
+ }
+
+ @Override
+ public void setBounds(int left, int top, int right, int bottom) {
+ super.setBounds(left, top, right, bottom);
+ baseIcon.setBounds(left, top, right, bottom);
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return baseIcon.getIntrinsicHeight();
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return baseIcon.getIntrinsicWidth();
+ }
+
+ @Override
+ public void setAlpha(int i) {
+ baseIcon.setAlpha(i);
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ baseIcon.setColorFilter(colorFilter);
+ paint.setColorFilter(colorFilter);
+ }
+
+ @Override
+ public void setTint(int tint) {
+ super.setTint(tint);
+ baseIcon.setTint(tint);
+ }
+
+ @Override
+ public void setTintList(ColorStateList tint) {
+ super.setTintList(tint);
+ baseIcon.setTintList(tint);
+ }
+
+ @Override
+ public void setTintMode(PorterDuff.Mode tintMode) {
+ super.setTintMode(tintMode);
+ baseIcon.setTintMode(tintMode);
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+ }
+
+ private static class MemoryGraphIcon extends QSTile.Icon {
+ long pss, limit;
+
+ public void setPss(long pss) {
+ this.pss = pss;
+ }
+
+ public void setHeapLimit(long limit) {
+ this.limit = limit;
+ }
+
+ @Override
+ public Drawable getDrawable(Context context) {
+ final MemoryIconDrawable drawable = new MemoryIconDrawable(context);
+ drawable.setPss(pss);
+ drawable.setLimit(limit);
+ return drawable;
+ }
+ }
+
+ public static class MemoryTile extends QSTileImpl<QSTile.State> {
+ public static final String TILE_SPEC = "dbg:mem";
+
+ private final GarbageMonitor gm;
+ private ProcessMemInfo pmi;
+
+ public MemoryTile(QSHost host) {
+ super(host);
+ gm = Dependency.get(GarbageMonitor.class);
+ }
+
+ @Override
+ public State newTileState() {
+ return new QSTile.State();
+ }
+
+ @Override
+ public Intent getLongClickIntent() {
+ return new Intent();
+ }
+
+ @Override
+ protected void handleClick() {
+ getHost().collapsePanels();
+ mHandler.post(gm::dumpHprofAndShare);
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return VIEW_UNKNOWN;
+ }
+
+ @Override
+ public void handleSetListening(boolean listening) {
+ if (gm != null) gm.setTile(listening ? this : null);
- // TODO(b/35345376): Turn this back on for debuggable builds after known leak fixed.
- private static final boolean ENABLED = Build.IS_DEBUGGABLE
- && SystemProperties.getBoolean("debug.enable_leak_reporting", false);
- private static final String FORCE_ENABLE = "sysui_force_garbage_monitor";
+ final ActivityManager am = mContext.getSystemService(ActivityManager.class);
+ if (listening && gm.mHeapLimit > 0) {
+ am.setWatchHeapLimit(1024 * gm.mHeapLimit); // why is this in bytes?
+ } else {
+ am.clearWatchHeapLimit();
+ }
+ }
+
+ @Override
+ public CharSequence getTileLabel() {
+ return getState().label;
+ }
+
+ @Override
+ protected void handleUpdateState(State state, Object arg) {
+ pmi = gm.getMemInfo(Process.myPid());
+ final MemoryGraphIcon icon = new MemoryGraphIcon();
+ icon.setHeapLimit(gm.mHeapLimit);
+ if (pmi != null) {
+ icon.setPss(pmi.currentPss);
+ state.label = mContext.getString(R.string.heap_dump_tile_name);
+ state.secondaryLabel =
+ String.format(
+ "pss: %s / %s",
+ formatBytes(pmi.currentPss * 1024),
+ formatBytes(gm.mHeapLimit * 1024));
+ } else {
+ icon.setPss(0);
+ state.label = "Dump SysUI";
+ state.secondaryLabel = null;
+ }
+ state.icon = icon;
+ }
+
+ public void update() {
+ refreshState();
+ }
+
+ public long getPss() {
+ return pmi != null ? pmi.currentPss : 0;
+ }
+
+ public long getHeapLimit() {
+ return gm != null ? gm.mHeapLimit : 0;
+ }
+ }
+
+ public static class ProcessMemInfo {
+ public long pid;
+ public String name;
+ public long startTime;
+ public long currentPss, currentUss;
+ public long[] pss = new long[256];
+ public long[] uss = new long[256];
+ public long max = 1;
+ public int head = 0;
+
+ public ProcessMemInfo(long pid, String name, long start) {
+ this.pid = pid;
+ this.name = name;
+ this.startTime = start;
+ }
+ public long getUptime() {
+ return System.currentTimeMillis() - startTime;
+ }
+ }
+
+ public static class Service extends SystemUI {
private GarbageMonitor mGarbageMonitor;
@Override
public void start() {
- boolean forceEnable = Settings.Secure.getInt(mContext.getContentResolver(),
- FORCE_ENABLE, 0) != 0;
- if (!ENABLED && !forceEnable) {
- return;
- }
+ boolean forceEnable =
+ Settings.Secure.getInt(
+ mContext.getContentResolver(), FORCE_ENABLE_LEAK_REPORTING, 0)
+ != 0;
mGarbageMonitor = Dependency.get(GarbageMonitor.class);
- mGarbageMonitor.start();
+ if (LEAK_REPORTING_ENABLED || forceEnable) {
+ mGarbageMonitor.startLeakMonitor();
+ }
+ if (HEAP_TRACKING_ENABLED || forceEnable) {
+ mGarbageMonitor.startHeapTracking();
+ }
+ }
+ }
+
+ private class BackgroundHeapCheckHandler extends Handler {
+ BackgroundHeapCheckHandler(Looper onLooper) {
+ super(onLooper);
+ if (Looper.getMainLooper().equals(onLooper)) {
+ throw new RuntimeException(
+ "BackgroundHeapCheckHandler may not run on the ui thread");
+ }
+ }
+
+ @Override
+ public void handleMessage(Message m) {
+ switch (m.what) {
+ case DO_GARBAGE_INSPECTION:
+ if (gcAndCheckGarbage()) {
+ postDelayed(GarbageMonitor.this::reinspectGarbageAfterGc, 100);
+ }
+
+ removeMessages(DO_GARBAGE_INSPECTION);
+ sendEmptyMessageDelayed(DO_GARBAGE_INSPECTION, GARBAGE_INSPECTION_INTERVAL);
+ break;
+
+ case DO_HEAP_TRACK:
+ update();
+ removeMessages(DO_HEAP_TRACK);
+ sendEmptyMessageDelayed(DO_HEAP_TRACK, HEAP_TRACK_INTERVAL);
+ break;
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index d7aedc4e53f1..b5071de6125f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -742,8 +742,11 @@ public class VolumeDialogImpl implements VolumeDialog {
updateVolumeRowH(row);
}
updateRingerH();
- mWindow.setTitle(mContext.getString(R.string.volume_dialog_title,
- getStreamLabelH(getActiveRow().ss)));
+ mWindow.setTitle(composeWindowTitle());
+ }
+
+ CharSequence composeWindowTitle() {
+ return mContext.getString(R.string.volume_dialog_title, getStreamLabelH(getActiveRow().ss));
}
private void updateVolumeRowH(VolumeRow row) {
@@ -1214,6 +1217,13 @@ public class VolumeDialogImpl implements VolumeDialog {
}
@Override
+ public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
+ // Activities populate their title here. Follow that example.
+ event.getText().add(composeWindowTitle());
+ return true;
+ }
+
+ @Override
public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
AccessibilityEvent event) {
rescheduleTimeoutH();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java
new file mode 100644
index 000000000000..e79c9d0c5455
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.keyguard;
+
+import static org.mockito.Mockito.verify;
+
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.LayoutInflater;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper(setAsMainLooper = true)
+public class KeyguardPinBasedInputViewTest extends SysuiTestCase {
+
+ @Mock
+ private PasswordTextView mPasswordTextView;
+ private KeyguardPinBasedInputView mKeyguardPinView;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ LayoutInflater inflater = LayoutInflater.from(getContext());
+ mKeyguardPinView =
+ (KeyguardPinBasedInputView) inflater.inflate(R.layout.keyguard_pin_view, null);
+ mKeyguardPinView.mPasswordEntry = mPasswordTextView;
+ }
+
+ @Test
+ public void onResume_requestsFocus() {
+ mKeyguardPinView.onResume(KeyguardSecurityView.SCREEN_ON);
+ verify(mPasswordTextView).requestFocus();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
index ab042d4ce491..2a4a5adb7d0f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
@@ -298,4 +298,13 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
assertEquals(3, mGroupRow.getNumUniqueChannels());
}
+
+ @Test
+ public void testIconScrollXAfterTranslationAndReset() throws Exception {
+ mGroupRow.setTranslation(50);
+ assertEquals(50, -mGroupRow.getEntry().expandedIcon.getScrollX());
+
+ mGroupRow.resetTranslation();
+ assertEquals(0, mGroupRow.getEntry().expandedIcon.getScrollX());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index b0530c85781f..65fd7f5f3651 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -33,9 +33,12 @@ import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -44,7 +47,6 @@ import android.app.INotificationManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
-import android.app.NotificationManager;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
@@ -52,7 +54,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
-import android.os.Looper;
+import android.os.IBinder;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
@@ -65,6 +67,7 @@ import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
@@ -100,7 +103,7 @@ public class NotificationInfoTest extends SysuiTestCase {
private StatusBarNotification mSbn;
@Rule public MockitoRule mockito = MockitoJUnit.rule();
- private Looper mLooper;
+ @Mock private MetricsLogger mMetricsLogger;
@Mock private INotificationManager mMockINotificationManager;
@Mock private PackageManager mMockPackageManager;
@Mock private NotificationBlockingHelperManager mBlockingHelperManager;
@@ -112,6 +115,7 @@ public class NotificationInfoTest extends SysuiTestCase {
mBlockingHelperManager);
mTestableLooper = TestableLooper.get(this);
mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
+ mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
// Inflate the layout
final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
mNotificationInfo = (NotificationInfo) layoutInflater.inflate(R.layout.notification_info,
@@ -301,6 +305,24 @@ public class NotificationInfoTest extends SysuiTestCase {
}
@Test
+ public void testLogBlockingHelperCounter_doesntLogForNormalGutsView() throws Exception {
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false);
+ mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
+ verify(mMetricsLogger, times(0)).count(anyString(), anyInt());
+ }
+
+ @Test
+ public void testLogBlockingHelperCounter_logsForBlockingHelper() throws Exception {
+ // Bind notification logs an event, so this counts as one invocation for the metrics logger.
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, true,
+ true);
+ mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
+ verify(mMetricsLogger, times(2)).count(anyString(), anyInt());
+ }
+
+ @Test
public void testOnClickListenerPassesNullChannelForBundle() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
@@ -471,6 +493,13 @@ public class NotificationInfoTest extends SysuiTestCase {
false /* isNonblockable */, true /* isForBlockingHelper */,
true /* isUserSentimentNegative */);
+ NotificationGuts guts = spy(new NotificationGuts(mContext, null));
+ when(guts.getWindowToken()).thenReturn(mock(IBinder.class));
+ doNothing().when(guts).animateClose(anyInt(), anyInt(), anyBoolean());
+ doNothing().when(guts).setExposed(anyBoolean(), anyBoolean());
+ guts.setGutsContent(mNotificationInfo);
+ mNotificationInfo.setGutsParent(guts);
+
mNotificationInfo.findViewById(R.id.keep).performClick();
verify(mBlockingHelperManager).dismissCurrentBlockingHelper();
@@ -495,6 +524,9 @@ public class NotificationInfoTest extends SysuiTestCase {
false /* isNonblockable */,
true /* isForBlockingHelper */,
false /* isUserSentimentNegative */);
+ NotificationGuts guts = mock(NotificationGuts.class);
+ doCallRealMethod().when(guts).closeControls(anyInt(), anyInt(), anyBoolean(), anyBoolean());
+ mNotificationInfo.setGutsParent(guts);
mNotificationInfo.closeControls(mNotificationInfo);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardPresentationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardPresentationTest.java
new file mode 100644
index 000000000000..54291536093c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardPresentationTest.java
@@ -0,0 +1,41 @@
+/*
+ * 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.statusbar.phone;
+
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class KeyguardPresentationTest extends SysuiTestCase {
+ @Test
+ public void testInflation_doesntCrash() {
+ LayoutInflater inflater = LayoutInflater.from(getContext());
+ inflater.inflate(R.layout.keyguard_presentation, null);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index d3cb5a6ecd8a..41cf86979627 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -78,6 +78,7 @@ import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.AppOpsListener;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.DndSuppressingNotificationsView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.FooterView;
import com.android.systemui.statusbar.FooterViewButton;
@@ -103,6 +104,7 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import org.junit.Before;
@@ -132,6 +134,7 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private ScrimController mScrimController;
@Mock private ArrayList<Entry> mNotificationList;
@Mock private FingerprintUnlockController mFingerprintUnlockController;
+ @Mock private ZenModeController mZenController;
@Mock private NotificationData mNotificationData;
// Mock dependencies:
@@ -163,6 +166,7 @@ public class StatusBarTest extends SysuiTestCase {
mDependency.injectTestDependency(NotificationListener.class, mNotificationListener);
mDependency.injectTestDependency(KeyguardMonitor.class, mock(KeyguardMonitorImpl.class));
mDependency.injectTestDependency(AppOpsListener.class, mock(AppOpsListener.class));
+ mDependency.injectTestDependency(ZenModeController.class, mZenController);
mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
@@ -213,7 +217,7 @@ public class StatusBarTest extends SysuiTestCase {
mRemoteInputManager, mock(NotificationGroupManager.class),
mock(FalsingManager.class), mock(StatusBarWindowManager.class),
mock(NotificationIconAreaController.class), mock(DozeScrimController.class),
- mock(NotificationShelf.class), mLockscreenUserManager,
+ mock(NotificationShelf.class), mLockscreenUserManager, mZenController,
mock(CommandQueue.class));
mStatusBar.mContext = mContext;
mStatusBar.mComponents = mContext.getComponents();
@@ -443,6 +447,30 @@ public class StatusBarTest extends SysuiTestCase {
}
@Test
+ public void testPeek_disabledStatusBar() {
+ Notification n = new Notification.Builder(getContext(), "a").build();
+ StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
+ UserHandle.of(0), null, 0);
+ NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ mStatusBar.disable(StatusBarManager.DISABLE_EXPAND, 0, false /* animate */);
+
+ assertFalse("The panel shouldn't allow peek while disabled",
+ mStatusBar.shouldPeek(entry, sbn));
+ }
+
+ @Test
+ public void testPeek_disabledNotificationShade() {
+ Notification n = new Notification.Builder(getContext(), "a").build();
+ StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
+ UserHandle.of(0), null, 0);
+ NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ mStatusBar.disable(0, StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false /* animate */);
+
+ assertFalse("The panel shouldn't allow peek while notitifcation shade disabled",
+ mStatusBar.shouldPeek(entry, sbn));
+ }
+
+ @Test
public void testLogHidden() {
try {
mStatusBar.handleVisibleToUserChanged(false);
@@ -652,6 +680,60 @@ public class StatusBarTest extends SysuiTestCase {
}
@Test
+ public void testDNDView_atEnd() {
+ // add footer
+ mStatusBar.reevaluateStyles();
+
+ // add notification
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+ mStackScroller.addContainerView(row);
+
+ mStatusBar.onUpdateRowStates();
+
+ // move dnd view to end
+ verify(mStackScroller).changeViewPosition(any(FooterView.class), eq(-1 /* end */));
+ verify(mStackScroller).changeViewPosition(any(DndSuppressingNotificationsView.class),
+ eq(-2 /* end */));
+ }
+
+ @Test
+ public void updateEmptyShade_nonNotificationsDndOff() {
+ mStatusBar.setBarStateForTest(StatusBarState.SHADE);
+ when(mNotificationData.getActiveNotifications()).thenReturn(new ArrayList<>());
+ assertEquals(0, mEntryManager.getNotificationData().getActiveNotifications().size());
+
+ mStatusBar.updateEmptyShadeView();
+ verify(mNotificationPanelView).showDndView(false);
+ verify(mNotificationPanelView).showEmptyShadeView(true);
+ }
+
+ @Test
+ public void updateEmptyShade_noNotificationsDndOn() {
+ mStatusBar.setBarStateForTest(StatusBarState.SHADE);
+ when(mNotificationData.getActiveNotifications()).thenReturn(new ArrayList<>());
+ assertEquals(0, mEntryManager.getNotificationData().getActiveNotifications().size());
+ when(mZenController.areNotificationsHiddenInShade()).thenReturn(true);
+
+ mStatusBar.updateEmptyShadeView();
+ verify(mNotificationPanelView).showDndView(true);
+ verify(mNotificationPanelView).showEmptyShadeView(false);
+ }
+
+ @Test
+ public void updateEmptyShade_yesNotificationsDndOff() {
+ mStatusBar.setBarStateForTest(StatusBarState.SHADE);
+ ArrayList<Entry> entries = new ArrayList<>();
+ entries.add(mock(Entry.class));
+ when(mNotificationData.getActiveNotifications()).thenReturn(entries);
+ assertEquals(1, mEntryManager.getNotificationData().getActiveNotifications().size());
+ when(mZenController.areNotificationsHiddenInShade()).thenReturn(false);
+
+ mStatusBar.updateEmptyShadeView();
+ verify(mNotificationPanelView).showDndView(false);
+ verify(mNotificationPanelView).showEmptyShadeView(false);
+ }
+
+ @Test
public void testSetState_changesIsFullScreenUserSwitcherState() {
mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
assertFalse(mStatusBar.isFullScreenUserSwitcherState());
@@ -697,6 +779,7 @@ public class StatusBarTest extends SysuiTestCase {
DozeScrimController dozeScrimController,
NotificationShelf notificationShelf,
NotificationLockscreenUserManager notificationLockscreenUserManager,
+ ZenModeController zenController,
CommandQueue commandQueue) {
mStatusBarKeyguardViewManager = man;
mUnlockMethodCache = unlock;
@@ -725,6 +808,7 @@ public class StatusBarTest extends SysuiTestCase {
mDozeScrimController = dozeScrimController;
mNotificationShelf = notificationShelf;
mLockscreenUserManager = notificationLockscreenUserManager;
+ mZenController = zenController;
mCommandQueue = commandQueue;
}
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 99c06e62d4bb..f3d79fd58982 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
@@ -87,8 +87,7 @@ public class SmartReplyViewTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
mReceiver = new BlockingQueueIntentReceiver();
mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION));
- mDependency.get(KeyguardDismissUtil.class).setDismissHandler(
- (action, cancelAction, afterKeyguardGone) -> action.onDismiss());
+ mDependency.get(KeyguardDismissUtil.class).setDismissHandler(action -> action.onDismiss());
mContainer = new View(mContext, null);
mView = SmartReplyView.inflate(mContext, null);
@@ -130,12 +129,7 @@ public class SmartReplyViewTest extends SysuiTestCase {
@Test
public void testSendSmartReply_keyguardCancelled() throws InterruptedException {
- mDependency.get(KeyguardDismissUtil.class).setDismissHandler(
- (action, cancelAction, afterKeyguardGone) -> {
- if (cancelAction != null) {
- cancelAction.run();
- }
- });
+ mDependency.get(KeyguardDismissUtil.class).setDismissHandler(action -> {});
setRepliesFromRemoteInput(TEST_CHOICES);
mView.getChildAt(2).performClick();
@@ -146,8 +140,7 @@ public class SmartReplyViewTest extends SysuiTestCase {
@Test
public void testSendSmartReply_waitsForKeyguard() throws InterruptedException {
AtomicReference<OnDismissAction> actionRef = new AtomicReference<>();
- mDependency.get(KeyguardDismissUtil.class).setDismissHandler(
- (action, cancelAction, afterKeyguardGone) -> actionRef.set(action));
+ mDependency.get(KeyguardDismissUtil.class).setDismissHandler(actionRef::set);
setRepliesFromRemoteInput(TEST_CHOICES);
mView.getChildAt(2).performClick();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
index eeb4209ccce4..3d17ec4469f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.stack;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
@@ -34,6 +35,7 @@ import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.TestableDependency;
+import com.android.systemui.statusbar.DndSuppressingNotificationsView;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.FooterView;
import com.android.systemui.statusbar.NotificationBlockingHelperManager;
@@ -69,6 +71,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Mock private NotificationGroupManager mGroupManager;
@Mock private ExpandHelper mExpandHelper;
@Mock private EmptyShadeView mEmptyShadeView;
+ @Mock private DndSuppressingNotificationsView mDndView;
@Before
@UiThreadTest
@@ -86,6 +89,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mStackScroller.setHeadsUpManager(mHeadsUpManager);
mStackScroller.setGroupManager(mGroupManager);
mStackScroller.setEmptyShadeView(mEmptyShadeView);
+ mStackScroller.setDndView(mDndView);
// Stub out functionality that isn't necessary to test.
doNothing().when(mBar)
@@ -120,40 +124,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
}
@Test
- public void updateEmptyView_dndSuppressing() {
- when(mEmptyShadeView.willBeGone()).thenReturn(true);
- when(mBar.areNotificationsHidden()).thenReturn(true);
-
- mStackScroller.updateEmptyShadeView(true);
-
- verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
- }
-
- @Test
- public void updateEmptyView_dndNotSuppressing() {
- mStackScroller.setEmptyShadeView(mEmptyShadeView);
- when(mEmptyShadeView.willBeGone()).thenReturn(true);
- when(mBar.areNotificationsHidden()).thenReturn(false);
-
- mStackScroller.updateEmptyShadeView(true);
-
- verify(mEmptyShadeView).setText(R.string.empty_shade_text);
- }
-
- @Test
- public void updateEmptyView_noNotificationsToDndSuppressing() {
- mStackScroller.setEmptyShadeView(mEmptyShadeView);
- when(mEmptyShadeView.willBeGone()).thenReturn(true);
- when(mBar.areNotificationsHidden()).thenReturn(false);
- mStackScroller.updateEmptyShadeView(true);
- verify(mEmptyShadeView).setText(R.string.empty_shade_text);
-
- when(mBar.areNotificationsHidden()).thenReturn(true);
- mStackScroller.updateEmptyShadeView(true);
- verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
- }
-
- @Test
@UiThreadTest
public void testSetExpandedHeight_blockingHelperManagerReceivedCallbacks() {
mStackScroller.setExpandedHeight(0f);
@@ -173,7 +143,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mStackScroller.updateFooterView(true, false);
- verify(view).setVisibility(View.VISIBLE);
+ verify(view).performVisibilityAnimation(eq(true), any());
verify(view).performSecondaryVisibilityAnimation(false);
}
@@ -186,7 +156,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mStackScroller.updateFooterView(true, true);
- verify(view).setVisibility(View.VISIBLE);
+ verify(view).performVisibilityAnimation(eq(true), any());
verify(view).performSecondaryVisibilityAnimation(true);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/leak/GarbageMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/leak/GarbageMonitorTest.java
index a3b258fb2ea2..c095472e0c62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/leak/GarbageMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/leak/GarbageMonitorTest.java
@@ -16,16 +16,18 @@
package com.android.systemui.util.leak;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.Context;
+import android.os.Looper;
import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
import com.android.systemui.SysuiTestCase;
@@ -34,7 +36,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
public class GarbageMonitorTest extends SysuiTestCase {
private LeakReporter mLeakReporter;
@@ -45,14 +48,17 @@ public class GarbageMonitorTest extends SysuiTestCase {
public void setup() {
mTrackedGarbage = mock(TrackedGarbage.class);
mLeakReporter = mock(LeakReporter.class);
- mGarbageMonitor = new TestableGarbageMonitor(
- new LeakDetector(null, mTrackedGarbage, null),
- mLeakReporter);
+ mGarbageMonitor =
+ new TestableGarbageMonitor(
+ mContext,
+ TestableLooper.get(this).getLooper(),
+ new LeakDetector(null, mTrackedGarbage, null),
+ mLeakReporter);
}
@Test
public void testCallbacks_getScheduled() {
- mGarbageMonitor.start();
+ mGarbageMonitor.startLeakMonitor();
mGarbageMonitor.runCallbacksOnce();
mGarbageMonitor.runCallbacksOnce();
mGarbageMonitor.runCallbacksOnce();
@@ -62,7 +68,7 @@ public class GarbageMonitorTest extends SysuiTestCase {
public void testNoGarbage_doesntDump() {
when(mTrackedGarbage.countOldGarbage()).thenReturn(0);
- mGarbageMonitor.start();
+ mGarbageMonitor.startLeakMonitor();
mGarbageMonitor.runCallbacksOnce();
mGarbageMonitor.runCallbacksOnce();
mGarbageMonitor.runCallbacksOnce();
@@ -74,7 +80,7 @@ public class GarbageMonitorTest extends SysuiTestCase {
public void testALittleGarbage_doesntDump() {
when(mTrackedGarbage.countOldGarbage()).thenReturn(4);
- mGarbageMonitor.start();
+ mGarbageMonitor.startLeakMonitor();
mGarbageMonitor.runCallbacksOnce();
mGarbageMonitor.runCallbacksOnce();
mGarbageMonitor.runCallbacksOnce();
@@ -86,7 +92,7 @@ public class GarbageMonitorTest extends SysuiTestCase {
public void testTransientGarbage_doesntDump() {
when(mTrackedGarbage.countOldGarbage()).thenReturn(100);
- mGarbageMonitor.start();
+ mGarbageMonitor.startLeakMonitor();
mGarbageMonitor.runInspectCallback();
when(mTrackedGarbage.countOldGarbage()).thenReturn(0);
@@ -100,56 +106,34 @@ public class GarbageMonitorTest extends SysuiTestCase {
public void testLotsOfPersistentGarbage_dumps() {
when(mTrackedGarbage.countOldGarbage()).thenReturn(100);
- mGarbageMonitor.start();
+ mGarbageMonitor.startLeakMonitor();
mGarbageMonitor.runCallbacksOnce();
verify(mLeakReporter).dumpLeak(anyInt());
}
private static class TestableGarbageMonitor extends GarbageMonitor {
- Runnable mInspectCallback;
- Runnable mReinspectCallback;
-
- public TestableGarbageMonitor(LeakDetector leakDetector,
+ public TestableGarbageMonitor(
+ Context context,
+ Looper looper,
+ LeakDetector leakDetector,
LeakReporter leakReporter) {
- super(null /* bgLooper */, leakDetector, leakReporter);
- }
-
- @Override
- void scheduleInspectGarbage(Runnable runnable) {
- assertNull("must not have more than one pending inspect callback", mInspectCallback);
- mInspectCallback = runnable;
+ super(context, looper, leakDetector, leakReporter);
}
void runInspectCallback() {
- assertNotNull("expected an inspect callback to be scheduled", mInspectCallback);
- Runnable callback = mInspectCallback;
- mInspectCallback = null;
- callback.run();
- }
-
- @Override
- void scheduleReinspectGarbage(Runnable runnable) {
- assertNull("must not have more than one reinspect callback", mReinspectCallback);
- mReinspectCallback = runnable;
+ startLeakMonitor();
}
void runReinspectCallback() {
- assertNotNull("expected a reinspect callback to be scheduled", mInspectCallback);
- maybeRunReinspectCallback();
- }
-
- void maybeRunReinspectCallback() {
- Runnable callback = mReinspectCallback;
- mReinspectCallback = null;
- if (callback != null) {
- callback.run();
- }
+ reinspectGarbageAfterGc();
}
void runCallbacksOnce() {
+ // Note that TestableLooper doesn't currently support delayed messages so we need to run
+ // callbacks explicitly.
runInspectCallback();
- maybeRunReinspectCallback();
+ runReinspectCallback();
}
}
} \ No newline at end of file
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index e33ef1fc8a6c..7dd85bad233d 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5717,6 +5717,29 @@ message MetricsEvent {
// OS: P
SETTINGS_ZEN_NOTIFICATIONS = 1400;
+ // An event category for slices.
+ // OPEN: Slice became visible.
+ // CLOSE: Slice became invisible.
+ // ACTION: Slice was tapped.
+ SLICE = 1401;
+
+ // The authority part of the slice URI
+ FIELD_SLICE_AUTHORITY = 1402;
+
+ // The path part of the slice URI
+ FIELD_SLICE_PATH = 1403;
+
+ // The authority part of the subslice URI
+ FIELD_SUBSLICE_AUTHORITY = 1404;
+
+ // The path part of the subslice URI
+ FIELD_SUBSLICE_PATH = 1405;
+
+ // OPEN: DND onboarding activity > don't update button
+ // CATEGORY: SETTINGS
+ // OS: P
+ ACTION_ZEN_ONBOARDING_KEEP_CURRENT_SETTINGS = 1406;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 3253f2e40692..51c0488dcd9f 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -219,6 +219,8 @@ public final class AutofillManagerService extends SystemService {
final String activePackageName = getActiveAutofillServicePackageName();
if (packageName.equals(activePackageName)) {
removeCachedServiceLocked(getChangingUserId());
+ } else {
+ handlePackageUpdateLocked(packageName);
}
}
}
@@ -250,6 +252,8 @@ public final class AutofillManagerService extends SystemService {
return true;
}
removeCachedServiceLocked(getChangingUserId());
+ } else {
+ handlePackageUpdateLocked(pkg);
}
}
}
@@ -274,6 +278,14 @@ public final class AutofillManagerService extends SystemService {
}
return serviceComponent.getPackageName();
}
+
+ @GuardedBy("mLock")
+ private void handlePackageUpdateLocked(String packageName) {
+ final int size = mServicesCache.size();
+ for (int i = 0; i < size; i++) {
+ mServicesCache.valueAt(i).handlePackageUpdateLocked(packageName);
+ }
+ }
};
// package changes
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 0bb29a7d1967..e582daa29335 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -626,9 +626,25 @@ final class AutofillManagerServiceImpl {
}
@GuardedBy("mLock")
+ void handlePackageUpdateLocked(String packageName) {
+ final ServiceInfo serviceInfo = mFieldClassificationStrategy.getServiceInfo();
+ if (serviceInfo != null && serviceInfo.packageName.equals(packageName)) {
+ resetExtServiceLocked();
+ }
+ }
+
+ @GuardedBy("mLock")
+ void resetExtServiceLocked() {
+ if (sVerbose) Slog.v(TAG, "reset autofill service.");
+ mFieldClassificationStrategy.reset();
+ }
+
+ @GuardedBy("mLock")
void destroyLocked() {
if (sVerbose) Slog.v(TAG, "destroyLocked()");
+ resetExtServiceLocked();
+
final int numSessions = mSessions.size();
final ArraySet<RemoteFillService> remoteFillServices = new ArraySet<>(numSessions);
for (int i = 0; i < numSessions; i++) {
diff --git a/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java b/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java
index da5220104e3c..9bec856e2308 100644
--- a/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java
+++ b/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java
@@ -83,7 +83,7 @@ final class FieldClassificationStrategy {
}
@Nullable
- private ServiceInfo getServiceInfo() {
+ ServiceInfo getServiceInfo() {
final String packageName =
mContext.getPackageManager().getServicesSystemSharedLibraryPackageName();
if (packageName == null) {
@@ -119,6 +119,18 @@ final class FieldClassificationStrategy {
return name;
}
+ void reset() {
+ synchronized (mLock) {
+ if (mServiceConnection != null) {
+ if (sDebug) Slog.d(TAG, "reset(): unbinding service.");
+ mContext.unbindService(mServiceConnection);
+ mServiceConnection = null;
+ } else {
+ if (sDebug) Slog.d(TAG, "reset(): service is not bound. Do nothing.");
+ }
+ }
+ }
+
/**
* Run a command, starting the service connection if necessary.
*/
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
index 821cca16bf60..44edabce72b6 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
@@ -421,7 +421,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor
// after the app's agent runs to handle its private filesystem
// contents, back up any OBB content it has on its behalf.
- if (mIncludeObbs) {
+ if (mIncludeObbs && !isSharedStorage) {
boolean obbOkay = obbConnection.backupObbs(pkg, out);
if (!obbOkay) {
throw new RuntimeException("Failure writing OBB stack for " + pkg);
diff --git a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
index 90baea0338e5..cc7304a93bbb 100644
--- a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
+++ b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
@@ -629,6 +629,8 @@ public class PerformBackupTask implements BackupRestoreTask {
mFullBackupTask.unregisterTask();
switch (mStatus) {
case BackupTransport.TRANSPORT_OK:
+ case BackupTransport.TRANSPORT_QUOTA_EXCEEDED:
+ case BackupTransport.TRANSPORT_PACKAGE_REJECTED:
BackupObserverUtils.sendBackupFinished(mObserver,
BackupManager.SUCCESS);
break;
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index d818bd6580f7..13503e60183f 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -48,6 +48,7 @@ import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.TimeUtils;
import android.util.Xml;
@@ -108,6 +109,9 @@ public class AppOpsService extends IAppOpsService.Stub {
// Write at most every 30 minutes.
static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
+ // How long we want for a drop in uid state to settle before applying it.
+ static final long STATE_SETTLE_TIME = 10*1000;
+
// Constant meaning that any UID should be matched when dispatching callbacks
private static final int UID_ANY = -2;
@@ -162,13 +166,6 @@ public class AppOpsService extends IAppOpsService.Stub {
"rc", // UID_STATE_CACHED
};
- static final String[] MODE_NAMES = new String[] {
- "allow", // MODE_ALLOWED
- "ignore", // MODE_IGNORED
- "deny", // MODE_ERRORED
- "default", // MODE_DEFAULT
- };
-
Context mContext;
final AtomicFile mFile;
final Handler mHandler;
@@ -194,6 +191,8 @@ public class AppOpsService extends IAppOpsService.Stub {
@VisibleForTesting
final SparseArray<UidState> mUidStates = new SparseArray<>();
+ long mLastUptime;
+
/*
* These are app op restrictions imposed per user from various parties.
*/
@@ -202,11 +201,17 @@ public class AppOpsService extends IAppOpsService.Stub {
@VisibleForTesting
static final class UidState {
public final int uid;
+
public int state = UID_STATE_CACHED;
+ public int pendingState = UID_STATE_CACHED;
+ public long pendingStateCommitTime;
+
public int startNesting;
public ArrayMap<String, Ops> pkgOps;
public SparseIntArray opModes;
+ public SparseBooleanArray foregroundOps;
+
public UidState(int uid) {
this.uid = uid;
}
@@ -220,6 +225,32 @@ public class AppOpsService extends IAppOpsService.Stub {
return (pkgOps == null || pkgOps.isEmpty())
&& (opModes == null || opModes.size() <= 0);
}
+
+ int evalMode(int mode) {
+ if (mode == AppOpsManager.MODE_FOREGROUND) {
+ return state <= UID_STATE_FOREGROUND_SERVICE
+ ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
+ }
+ return mode;
+ }
+
+ public void evalForegroundOps() {
+ SparseBooleanArray which = null;
+ if (pkgOps != null) {
+ for (int i = pkgOps.size() - 1; i >= 0; i--) {
+ Ops ops = pkgOps.valueAt(i);
+ for (int j = ops.size() - 1; j >= 0; j--) {
+ if (ops.valueAt(j).mode == AppOpsManager.MODE_FOREGROUND) {
+ if (which == null) {
+ which = new SparseBooleanArray();
+ }
+ which.put(ops.keyAt(j), true);
+ }
+ }
+ }
+ }
+ foregroundOps = which;
+ }
}
final static class Ops extends SparseArray<Op> {
@@ -267,6 +298,10 @@ public class AppOpsService extends IAppOpsService.Stub {
}
return false;
}
+
+ int getMode() {
+ return uidState.evalMode(mode);
+ }
}
final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
@@ -575,7 +610,16 @@ public class AppOpsService extends IAppOpsService.Stub {
synchronized (this) {
final UidState uidState = getUidStateLocked(uid, true);
final int newState = PROCESS_STATE_TO_UID_STATE[procState];
- if (uidState != null && uidState.state != newState) {
+ if (uidState != null && uidState.pendingState != newState) {
+ if (newState < uidState.state) {
+ // We are moving to a more important state, always do it immediately.
+ uidState.state = newState;
+ uidState.pendingStateCommitTime = 0;
+ } else if (uidState.pendingStateCommitTime == 0) {
+ // We are moving to a less important state for the first time,
+ // delay the application for a bit.
+ uidState.pendingStateCommitTime = SystemClock.uptimeMillis() + STATE_SETTLE_TIME;
+ }
if (uidState.startNesting != 0) {
// There is some actively running operation... need to find it
// and appropriately update its state.
@@ -585,13 +629,13 @@ public class AppOpsService extends IAppOpsService.Stub {
for (int j = ops.size() - 1; j >= 0; j--) {
final Op op = ops.valueAt(j);
if (op.startNesting > 0) {
- op.time[uidState.state] = now;
+ op.time[uidState.pendingState] = now;
op.time[newState] = now;
}
}
}
}
- uidState.state = newState;
+ uidState.pendingState = newState;
}
}
}
@@ -887,6 +931,9 @@ public class AppOpsService extends IAppOpsService.Stub {
if (op != null) {
if (op.mode != mode) {
op.mode = mode;
+ if (uidState != null) {
+ uidState.evalForegroundOps();
+ }
ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
if (cbs != null) {
if (repCbs == null) {
@@ -1046,6 +1093,7 @@ public class AppOpsService extends IAppOpsService.Stub {
Map<String, Ops> packages = uidState.pkgOps;
Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
+ boolean uidChanged = false;
while (it.hasNext()) {
Map.Entry<String, Ops> ent = it.next();
String packageName = ent.getKey();
@@ -1060,6 +1108,7 @@ public class AppOpsService extends IAppOpsService.Stub {
&& curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
changed = true;
+ uidChanged = true;
callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
mOpModeWatchers.get(curOp.op));
callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
@@ -1076,6 +1125,9 @@ public class AppOpsService extends IAppOpsService.Stub {
if (uidState.isDefault()) {
mUidStates.remove(uidState.uid);
}
+ if (uidChanged) {
+ uidState.evalForegroundOps();
+ }
}
if (changed) {
@@ -1197,7 +1249,7 @@ public class AppOpsService extends IAppOpsService.Stub {
if (op == null) {
return AppOpsManager.opToDefaultMode(code);
}
- return op.mode;
+ return op.mode == AppOpsManager.MODE_FOREGROUND ? AppOpsManager.MODE_ALLOWED : op.mode;
}
}
@@ -1352,9 +1404,9 @@ public class AppOpsService extends IAppOpsService.Stub {
// If there is a non-default per UID policy (we set UID op mode only if
// non-default) it takes over, otherwise use the per package policy.
if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
- final int uidMode = uidState.opModes.get(switchCode);
+ final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
if (uidMode != AppOpsManager.MODE_ALLOWED) {
- if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + op.mode + " for code "
+ if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
+ packageName);
op.rejectTime[uidState.state] = System.currentTimeMillis();
@@ -1362,12 +1414,13 @@ public class AppOpsService extends IAppOpsService.Stub {
}
} else {
final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
- if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
- if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + op.mode + " for code "
+ final int mode = switchOp.getMode();
+ if (mode != AppOpsManager.MODE_ALLOWED) {
+ if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
+ packageName);
op.rejectTime[uidState.state] = System.currentTimeMillis();
- return switchOp.mode;
+ return mode;
}
}
if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
@@ -1458,10 +1511,10 @@ public class AppOpsService extends IAppOpsService.Stub {
// If there is a non-default per UID policy (we set UID op mode only if
// non-default) it takes over, otherwise use the per package policy.
if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
- final int uidMode = uidState.opModes.get(switchCode);
+ final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
if (uidMode != AppOpsManager.MODE_ALLOWED
&& (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
- if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + op.mode + " for code "
+ if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
+ resolvedPackageName);
op.rejectTime[uidState.state] = System.currentTimeMillis();
@@ -1469,13 +1522,14 @@ public class AppOpsService extends IAppOpsService.Stub {
}
} else {
final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
- if (switchOp.mode != AppOpsManager.MODE_ALLOWED
- && (!startIfModeDefault || switchOp.mode != AppOpsManager.MODE_DEFAULT)) {
- if (DEBUG) Slog.d(TAG, "startOperation: reject #" + op.mode + " for code "
+ final int mode = switchOp.getMode();
+ if (mode != AppOpsManager.MODE_ALLOWED
+ && (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
+ if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
+ resolvedPackageName);
op.rejectTime[uidState.state] = System.currentTimeMillis();
- return switchOp.mode;
+ return mode;
}
}
if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
@@ -1642,6 +1696,19 @@ public class AppOpsService extends IAppOpsService.Stub {
}
uidState = new UidState(uid);
mUidStates.put(uid, uidState);
+ } else {
+ if (uidState.pendingStateCommitTime != 0) {
+ if (uidState.pendingStateCommitTime < mLastUptime) {
+ uidState.state = uidState.pendingState;
+ uidState.pendingStateCommitTime = 0;
+ } else {
+ mLastUptime = SystemClock.uptimeMillis();
+ if (uidState.pendingStateCommitTime < mLastUptime) {
+ uidState.state = uidState.pendingState;
+ uidState.pendingStateCommitTime = 0;
+ }
+ }
+ }
}
return uidState;
}
@@ -1870,6 +1937,7 @@ public class AppOpsService extends IAppOpsService.Stub {
if (uidState.pkgOps == null) {
continue;
}
+ boolean changed = false;
for (int j = 0; j < uidState.pkgOps.size(); j++) {
Ops ops = uidState.pkgOps.valueAt(j);
if (ops != null) {
@@ -1879,9 +1947,13 @@ public class AppOpsService extends IAppOpsService.Stub {
AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
copy.mode = op.mode;
ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
+ changed = true;
}
}
}
+ if (changed) {
+ uidState.evalForegroundOps();
+ }
}
}
@@ -2077,6 +2149,10 @@ public class AppOpsService extends IAppOpsService.Stub {
XmlUtils.skipCurrentTag(parser);
}
}
+ UidState uidState = getUidStateLocked(uid, false);
+ if (uidState != null) {
+ uidState.evalForegroundOps();
+ }
}
void writeState() {
@@ -2152,12 +2228,12 @@ public class AppOpsService extends IAppOpsService.Stub {
out.attribute(null, "m", Integer.toString(op.getMode()));
}
for (int k = 0; k < _NUM_UID_STATE; k++) {
- final long time = op.getTimeFor(k);
+ final long time = op.getLastTimeFor(k);
if (time != 0) {
out.attribute(null, UID_STATE_TIME_ATTRS[k],
Long.toString(time));
}
- final long rejectTime = op.getRejectTimeFor(k);
+ final long rejectTime = op.getLastRejectTimeFor(k);
if (rejectTime != 0) {
out.attribute(null, UID_STATE_REJECT_ATTRS[k],
Long.toString(rejectTime));
@@ -2229,7 +2305,7 @@ public class AppOpsService extends IAppOpsService.Stub {
dumpCommandHelp(pw);
}
- private int strOpToOp(String op, PrintWriter err) {
+ static private int strOpToOp(String op, PrintWriter err) {
try {
return AppOpsManager.strOpToOp(op);
} catch (IllegalArgumentException e) {
@@ -2247,8 +2323,8 @@ public class AppOpsService extends IAppOpsService.Stub {
}
int strModeToMode(String modeStr, PrintWriter err) {
- for (int i = MODE_NAMES.length - 1; i >= 0; i--) {
- if (MODE_NAMES[i].equals(modeStr)) {
+ for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
+ if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
return i;
}
}
@@ -2470,7 +2546,7 @@ public class AppOpsService extends IAppOpsService.Stub {
if (ops == null || ops.size() <= 0) {
pw.println("No operations.");
if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) {
- pw.println("Default mode: " + AppOpsManager.modeToString(
+ pw.println("Default mode: " + AppOpsManager.modeToName(
AppOpsManager.opToDefaultMode(shell.op)));
}
return 0;
@@ -2482,7 +2558,7 @@ public class AppOpsService extends IAppOpsService.Stub {
AppOpsManager.OpEntry ent = entries.get(j);
pw.print(AppOpsManager.opToName(ent.getOp()));
pw.print(": ");
- pw.print(AppOpsManager.modeToString(ent.getMode()));
+ pw.print(AppOpsManager.modeToName(ent.getMode()));
if (ent.getTime() != 0) {
pw.print("; time=");
TimeUtils.formatDuration(now - ent.getTime(), pw);
@@ -2636,7 +2712,10 @@ public class AppOpsService extends IAppOpsService.Stub {
private void dumpHelp(PrintWriter pw) {
pw.println("AppOps service (appops) dump options:");
- pw.println(" none");
+ pw.println(" -h");
+ pw.println(" Print this help text.");
+ pw.println(" --op [OP]");
+ pw.println(" Limit output to data associated with the given app op code.");
}
private void dumpTimesLocked(PrintWriter pw, String firstPrefix, String prefix, long[] times,
@@ -2671,6 +2750,8 @@ public class AppOpsService extends IAppOpsService.Stub {
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
+ int dumpOp = -1;
+
if (args != null) {
for (int i=0; i<args.length; i++) {
String arg = args[i];
@@ -2679,6 +2760,16 @@ public class AppOpsService extends IAppOpsService.Stub {
return;
} else if ("-a".equals(arg)) {
// dump all data
+ } else if ("--op".equals(arg)) {
+ i++;
+ if (i >= args.length) {
+ pw.println("No argument for --op option");
+ return;
+ }
+ dumpOp = Shell.strOpToOp(args[i], pw);
+ if (dumpOp < 0) {
+ return;
+ }
} else if (arg.length() > 0 && arg.charAt(0) == '-'){
pw.println("Unknown option: " + arg);
return;
@@ -2693,13 +2784,21 @@ public class AppOpsService extends IAppOpsService.Stub {
pw.println("Current AppOps Service state:");
final long now = System.currentTimeMillis();
final long nowElapsed = SystemClock.elapsedRealtime();
+ final long nowUptime = SystemClock.uptimeMillis();
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
final Date date = new Date();
boolean needSep = false;
if (mOpModeWatchers.size() > 0) {
needSep = true;
- pw.println(" Op mode watchers:");
+ boolean printedHeader = false;
for (int i=0; i<mOpModeWatchers.size(); i++) {
+ if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
+ continue;
+ }
+ if (!printedHeader) {
+ pw.println(" Op mode watchers:");
+ printedHeader = true;
+ }
pw.print(" Op "); pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
pw.println(":");
ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
@@ -2722,7 +2821,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
}
- if (mModeWatchers.size() > 0) {
+ if (mModeWatchers.size() > 0 && dumpOp < 0) {
needSep = true;
pw.println(" All op mode watchers:");
for (int i=0; i<mModeWatchers.size(); i++) {
@@ -2733,12 +2832,19 @@ public class AppOpsService extends IAppOpsService.Stub {
}
if (mActiveWatchers.size() > 0) {
needSep = true;
- pw.println(" All op active watchers:");
+ boolean printedHeader = false;
for (int i = 0; i < mActiveWatchers.size(); i++) {
final SparseArray<ActiveCallback> activeWatchers = mActiveWatchers.valueAt(i);
if (activeWatchers.size() <= 0) {
continue;
}
+ if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
+ continue;
+ }
+ if (!printedHeader) {
+ pw.println(" All op active watchers:");
+ printedHeader = true;
+ }
pw.print(" ");
pw.print(Integer.toHexString(System.identityHashCode(
mActiveWatchers.keyAt(i))));
@@ -2746,6 +2852,9 @@ public class AppOpsService extends IAppOpsService.Stub {
pw.print(" [");
final int opCount = activeWatchers.size();
for (i = 0; i < opCount; i++) {
+ if (i > 0) {
+ pw.print(' ');
+ }
pw.print(AppOpsManager.opToName(activeWatchers.keyAt(i)));
if (i < opCount - 1) {
pw.print(',');
@@ -2758,15 +2867,30 @@ public class AppOpsService extends IAppOpsService.Stub {
}
if (mClients.size() > 0) {
needSep = true;
- pw.println(" Clients:");
+ boolean printedHeader = false;
for (int i=0; i<mClients.size(); i++) {
- pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":");
+ boolean printedClient = false;
ClientState cs = mClients.valueAt(i);
- pw.print(" "); pw.println(cs);
if (cs.mStartedOps.size() > 0) {
- pw.println(" Started ops:");
+ boolean printedStarted = false;
for (int j=0; j<cs.mStartedOps.size(); j++) {
Op op = cs.mStartedOps.get(j);
+ if (dumpOp >= 0 && op.op != dumpOp) {
+ continue;
+ }
+ if (!printedHeader) {
+ pw.println(" Clients:");
+ printedHeader = true;
+ }
+ if (!printedClient) {
+ pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":");
+ pw.print(" "); pw.println(cs);
+ printedClient = true;
+ }
+ if (!printedStarted) {
+ pw.println(" Started ops:");
+ printedStarted = true;
+ }
pw.print(" "); pw.print("uid="); pw.print(op.uid);
pw.print(" pkg="); pw.print(op.packageName);
pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
@@ -2774,7 +2898,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
}
- if (mAudioRestrictions.size() > 0) {
+ if (mAudioRestrictions.size() > 0 && dumpOp < 0) {
boolean printedHeader = false;
for (int o=0; o<mAudioRestrictions.size(); o++) {
final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
@@ -2789,7 +2913,7 @@ public class AppOpsService extends IAppOpsService.Stub {
pw.print(" "); pw.print(op);
pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
Restriction r = restrictions.valueAt(i);
- pw.print(": mode="); pw.println(MODE_NAMES[r.mode]);
+ pw.print(": mode="); pw.println(AppOpsManager.modeToName(r.mode));
if (!r.exceptionPackages.isEmpty()) {
pw.println(" Exceptions:");
for (int j=0; j<r.exceptionPackages.size(); j++) {
@@ -2804,38 +2928,83 @@ public class AppOpsService extends IAppOpsService.Stub {
}
for (int i=0; i<mUidStates.size(); i++) {
UidState uidState = mUidStates.valueAt(i);
+ final SparseIntArray opModes = uidState.opModes;
+ final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
+
+ if (dumpOp >= 0) {
+ boolean hasOp = uidState.opModes != null
+ && uidState.opModes.indexOfKey(dumpOp) >= 0;
+ if (pkgOps != null) {
+ for (int pkgi = 0; !hasOp && pkgi < pkgOps.size(); pkgi++) {
+ Ops ops = pkgOps.valueAt(pkgi);
+ if (ops != null && ops.indexOfKey(dumpOp) >= 0) {
+ hasOp = true;
+ continue;
+ }
+ }
+ }
+ if (!hasOp) {
+ continue;
+ }
+ }
pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
pw.print(" state=");
pw.println(UID_STATE_NAMES[uidState.state]);
+ if (uidState.state != uidState.pendingState) {
+ pw.print(" pendingState=");
+ pw.println(UID_STATE_NAMES[uidState.pendingState]);
+ }
+ if (uidState.pendingStateCommitTime != 0) {
+ pw.print(" pendingStateCommitTime=");
+ TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowUptime, pw);
+ pw.println();
+ }
if (uidState.startNesting != 0) {
pw.print(" startNesting=");
pw.println(uidState.startNesting);
}
+ if (uidState.foregroundOps != null) {
+ pw.println(" foregroundOps:");
+ for (int j = 0; j < uidState.foregroundOps.size(); j++) {
+ pw.print(" ");
+ pw.println(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
+ }
+ }
needSep = true;
- SparseIntArray opModes = uidState.opModes;
if (opModes != null) {
final int opModeCount = opModes.size();
for (int j = 0; j < opModeCount; j++) {
final int code = opModes.keyAt(j);
final int mode = opModes.valueAt(j);
+ if (dumpOp >= 0 && dumpOp != code) {
+ continue;
+ }
pw.print(" "); pw.print(AppOpsManager.opToName(code));
- pw.print(": mode="); pw.println(MODE_NAMES[mode]);
+ pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
}
}
- ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
if (pkgOps == null) {
continue;
}
- for (Ops ops : pkgOps.values()) {
- pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
+ for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
+ Ops ops = pkgOps.valueAt(pkgi);
+ boolean printedPackage = false;
for (int j=0; j<ops.size(); j++) {
Op op = ops.valueAt(j);
+ if (dumpOp >= 0 && dumpOp != op.op) {
+ continue;
+ }
+ if (!printedPackage) {
+ pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
+ printedPackage = true;
+ }
pw.print(" "); pw.print(AppOpsManager.opToName(op.op));
- pw.print(" ("); pw.print(MODE_NAMES[op.mode]); pw.println("): ");
+ pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
+ pw.println("): ");
dumpTimesLocked(pw,
" Access: ",
" ", op.time, now, sdf, date);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 9994462531b2..72f9d749865b 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -132,6 +132,7 @@ import com.android.internal.net.NetworkStatsFactory;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnInfo;
import com.android.internal.net.VpnProfile;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
@@ -1992,13 +1993,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
return ret;
}
- private boolean argsContain(String[] args, String target) {
- for (String arg : args) {
- if (target.equals(arg)) return true;
- }
- return false;
- }
-
private void dumpNetworkDiagnostics(IndentingPrintWriter pw) {
final List<NetworkDiagnostics> netDiags = new ArrayList<NetworkDiagnostics>();
final long DIAG_TIME_MS = 5000;
@@ -2027,10 +2021,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
if (asProto) return;
- if (argsContain(args, DIAG_ARG)) {
+ if (ArrayUtils.contains(args, DIAG_ARG)) {
dumpNetworkDiagnostics(pw);
return;
- } else if (argsContain(args, TETHERING_ARG)) {
+ } else if (ArrayUtils.contains(args, TETHERING_ARG)) {
mTethering.dump(fd, pw, args);
return;
}
@@ -2098,7 +2092,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
pw.println();
mMultipathPolicyTracker.dump(pw);
- if (argsContain(args, SHORT_ARG) == false) {
+ if (ArrayUtils.contains(args, SHORT_ARG) == false) {
pw.println();
synchronized (mValidationLogs) {
pw.println("mValidationLogs (most recent first):");
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 2465ba2e21bd..d86973461ade 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -33,10 +33,11 @@ option java_package com.android.server
# It logs the time remaining before the device would've normally gone to sleep without the request.
2731 power_soft_sleep_requested (savedwaketimems|2)
# Power save state has changed. See BatterySaverController.java for the details.
-2739 battery_saver_mode (prevOffOrOn|1|5),(nowOffOrOn|1|5),(interactive|1|5),(features|3|5)
+2739 battery_saver_mode (prevOffOrOn|1|5),(nowOffOrOn|1|5),(interactive|1|5),(features|3|5),(reason|1|5)
27390 battery_saving_stats (batterySaver|1|5),(interactive|1|5),(doze|1|5),(delta_duration|2|3),(delta_battery_drain|1|1),(delta_battery_drain_percent|1|6),(total_duration|2|3),(total_battery_drain|1|1),(total_battery_drain_percent|1|6)
# Note when the user activity timeout has been overriden by ActivityManagerService
27391 user_activity_timeout_override (override|2|3)
+27392 battery_saver_setting (threshold|1)
#
# Leave IDs through 2740 for more power logs (2730 used by battery_discharge above)
diff --git a/services/core/java/com/android/server/FgThread.java b/services/core/java/com/android/server/FgThread.java
index 021bfaa10230..fe30057fc820 100644
--- a/services/core/java/com/android/server/FgThread.java
+++ b/services/core/java/com/android/server/FgThread.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.os.Handler;
+import android.os.Looper;
import android.os.Trace;
/**
@@ -28,6 +29,9 @@ import android.os.Trace;
* to be delayed for a user-noticeable amount of time.
*/
public final class FgThread extends ServiceThread {
+ private static final long SLOW_DISPATCH_THRESHOLD_MS = 100;
+ private static final long SLOW_DELIVERY_THRESHOLD_MS = 200;
+
private static FgThread sInstance;
private static Handler sHandler;
@@ -39,7 +43,10 @@ public final class FgThread extends ServiceThread {
if (sInstance == null) {
sInstance = new FgThread();
sInstance.start();
- sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
+ final Looper looper = sInstance.getLooper();
+ looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
+ looper.setSlowLogThresholdMs(
+ SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
sHandler = new Handler(sInstance.getLooper());
}
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 6c35bdae5a3e..00302b2fc6da 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2541,11 +2541,6 @@ class StorageManagerService extends IStorageManager.Stub
synchronized (mLock) {
mLocalUnlockedUsers = ArrayUtils.appendInt(mLocalUnlockedUsers, userId);
}
- if (userId == UserHandle.USER_SYSTEM) {
- String propertyName = "sys.user." + userId + ".ce_available";
- Slog.d(TAG, "Setting property: " + propertyName + "=true");
- SystemProperties.set(propertyName, "true");
- }
}
@Override
@@ -2685,7 +2680,8 @@ class StorageManagerService extends IStorageManager.Stub
}
// Ignore requests to create directories if CE storage is not available
- if (!SystemProperties.getBoolean(propertyName, false)) {
+ if ((userId == UserHandle.USER_SYSTEM)
+ && !SystemProperties.getBoolean(propertyName, false)) {
throw new IllegalStateException("Failed to prepare " + appPath);
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 41f413d5f07d..607db4efb63e 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -117,10 +117,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
return (onSubscriptionsChangedListenerCallback != null);
}
- boolean canReadPhoneState() {
+ boolean canReadCallLog() {
try {
- return TelephonyPermissions.checkReadPhoneState(
- context, subId, callerPid, callerUid, callingPackage, "listen");
+ return TelephonyPermissions.checkReadCallLog(
+ context, subId, callerPid, callerUid, callingPackage);
} catch (SecurityException e) {
return false;
}
@@ -667,8 +667,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
private String getCallIncomingNumber(Record record, int phoneId) {
- // Hide the number if record's process can't currently read phone state.
- return record.canReadPhoneState() ? mCallIncomingNumber[phoneId] : "";
+ // Only reveal the incoming number if the record has read call log permission.
+ return record.canReadCallLog() ? mCallIncomingNumber[phoneId] : "";
}
private Record add(IBinder binder) {
@@ -729,13 +729,13 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- public void notifyCallState(int state, String incomingNumber) {
+ public void notifyCallState(int state, String phoneNumber) {
if (!checkNotifyPermission("notifyCallState()")) {
return;
}
if (VDBG) {
- log("notifyCallState: state=" + state + " incomingNumber=" + incomingNumber);
+ log("notifyCallState: state=" + state + " phoneNumber=" + phoneNumber);
}
synchronized (mRecords) {
@@ -743,8 +743,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_CALL_STATE) &&
(r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
try {
- String incomingNumberOrEmpty = r.canReadPhoneState() ? incomingNumber : "";
- r.callback.onCallStateChanged(state, incomingNumberOrEmpty);
+ // Ensure the listener has read call log permission; if they do not return
+ // an empty phone number.
+ String phoneNumberOrEmpty = r.canReadCallLog() ? phoneNumber : "";
+ r.callback.onCallStateChanged(state, phoneNumberOrEmpty);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
@@ -755,7 +757,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
// Called only by Telecomm to communicate call state across different phone accounts. So
// there is no need to add a valid subId or slotId.
- broadcastCallStateChanged(state, incomingNumber,
+ broadcastCallStateChanged(state, phoneNumber,
SubscriptionManager.INVALID_PHONE_INDEX,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
}
@@ -1571,9 +1573,6 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
intent.putExtra(PhoneConstants.STATE_KEY,
PhoneConstantConversions.convertCallState(state).toString());
- if (!TextUtils.isEmpty(incomingNumber)) {
- intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
- }
// If a valid subId was specified, we should fire off a subId-specific state
// change intent and include the subId.
@@ -1589,13 +1588,20 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
// Wakeup apps for the (SUBSCRIPTION_)PHONE_STATE broadcast.
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ Intent intentWithPhoneNumber = new Intent(intent);
+ if (!TextUtils.isEmpty(incomingNumber)) {
+ intentWithPhoneNumber.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
+ }
// Send broadcast twice, once for apps that have PRIVILEGED permission and once for those
// that have the runtime one
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
+ mContext.sendBroadcastAsUser(intentWithPhoneNumber, UserHandle.ALL,
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
android.Manifest.permission.READ_PHONE_STATE,
AppOpsManager.OP_READ_PHONE_STATE);
+ mContext.sendBroadcastAsUserMultiplePermissions(intentWithPhoneNumber, UserHandle.ALL,
+ new String[] { android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_CALL_LOG});
}
private void broadcastDataConnectionStateChanged(int state,
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index 26a8cf74d245..f24d8cd0d3b5 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -71,6 +71,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.function.Predicate;
public class TextServicesManagerService extends ITextServicesManager.Stub {
private static final String TAG = TextServicesManagerService.class.getSimpleName();
@@ -396,10 +397,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
final String packageName = sci.getPackageName();
final int change = isPackageDisappearing(packageName);
if (DBG) Slog.d(TAG, "Changing package name: " + packageName);
- if (// Package disappearing
- change == PACKAGE_PERMANENT_CHANGE || change == PACKAGE_TEMPORARY_CHANGE
- // Package modified
- || isPackageModified(packageName)) {
+ if (change == PACKAGE_PERMANENT_CHANGE || change == PACKAGE_TEMPORARY_CHANGE) {
SpellCheckerInfo availSci =
findAvailSystemSpellCheckerLocked(packageName, tsd);
// Set the spell checker settings if different than before
@@ -885,6 +883,11 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
}
synchronized (mLock) {
mListeners.unregister(listener);
+ final IBinder scListenerBinder = listener.asBinder();
+ final Predicate<SessionRequest> removeCondition =
+ request -> request.mScListener.asBinder() == scListenerBinder;
+ mPendingSessionRequests.removeIf(removeCondition);
+ mOnGoingSessionRequests.removeIf(removeCondition);
cleanLocked();
}
}
@@ -934,6 +937,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
if (mUnbindCalled) {
return;
}
+ mListeners.register(request.mScListener);
if (!mConnected) {
mPendingSessionRequests.add(request);
return;
@@ -959,7 +963,6 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
if (mOnGoingSessionRequests.remove(request)) {
try {
request.mTsListener.onServiceConnected(newSession);
- mListeners.register(request.mScListener);
} catch (RemoteException e) {
// Technically this can happen if the spell checker client app is already
// dead. We can just forget about this request; the request is already
diff --git a/services/core/java/com/android/server/UiThread.java b/services/core/java/com/android/server/UiThread.java
index f81307429ae0..b2fa6846a6d0 100644
--- a/services/core/java/com/android/server/UiThread.java
+++ b/services/core/java/com/android/server/UiThread.java
@@ -28,6 +28,7 @@ import android.os.Trace;
*/
public final class UiThread extends ServiceThread {
private static final long SLOW_DISPATCH_THRESHOLD_MS = 100;
+ private static final long SLOW_DELIVERY_THRESHOLD_MS = 200;
private static UiThread sInstance;
private static Handler sHandler;
@@ -48,7 +49,8 @@ public final class UiThread extends ServiceThread {
sInstance.start();
final Looper looper = sInstance.getLooper();
looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
- looper.setSlowDispatchThresholdMs(SLOW_DISPATCH_THRESHOLD_MS);
+ looper.setSlowLogThresholdMs(
+ SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
sHandler = new Handler(sInstance.getLooper());
}
}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 2e258c140efc..f749fe72090e 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -92,6 +92,7 @@ public class Watchdog extends Thread {
public static final List<String> HAL_INTERFACES_OF_INTEREST = Arrays.asList(
"android.hardware.audio@2.0::IDevicesFactory",
+ "android.hardware.audio@4.0::IDevicesFactory",
"android.hardware.bluetooth@1.0::IBluetoothHci",
"android.hardware.camera.provider@2.4::ICameraProvider",
"android.hardware.graphics.composer@2.1::IComposer",
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 193d3f498317..a8e63f6695d4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5049,9 +5049,20 @@ public class ActivityManagerService extends IActivityManager.Stub
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
+ return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
+ resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
+ true /*validateIncomingUser*/);
+ }
+
+ public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
+ Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
+ int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
+ boolean validateIncomingUser) {
enforceNotIsolatedCaller("startActivity");
- userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
- userId, false, ALLOW_FULL_ONLY, "startActivity", null);
+
+ userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser,
+ Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
+
// TODO: Switch to user app stacks here.
return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
@@ -26344,6 +26355,16 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
+ public int startActivityAsUser(IApplicationThread caller, String callerPacakge,
+ Intent intent, Bundle options, int userId) {
+ return ActivityManagerService.this.startActivityAsUser(
+ caller, callerPacakge, intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, options, userId,
+ false /*validateIncomingUser*/);
+ }
+
+ @Override
public int getUidProcessState(int uid) {
return getUidState(uid);
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 16c5969a9167..e73f42fa4264 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1626,6 +1626,10 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
if (parent != null) {
parent.onActivityStateChanged(this, state, reason);
}
+
+ if (state == STOPPING) {
+ mWindowContainerController.notifyAppStopping();
+ }
}
ActivityState getState() {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index e86850e66071..a85df03e97f6 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
@@ -1784,6 +1785,14 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
final int otherWindowingMode = other.getWindowingMode();
if (otherWindowingMode == WINDOWING_MODE_FULLSCREEN) {
+ // In this case the home stack isn't resizeable even though we are in split-screen
+ // mode. We still want the primary splitscreen stack to be visible as there will be
+ // a slight hint of it in the status bar area above the non-resizeable home
+ // activity.
+ if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ && other.getActivityType() == ACTIVITY_TYPE_HOME) {
+ return true;
+ }
if (other.isStackTranslucent(starting)) {
// Can be visible behind a translucent fullscreen stack.
continue;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index b1ca64eaf7a0..4ace68947957 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1315,10 +1315,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return aInfo;
}
- ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId) {
- return resolveIntent(intent, resolvedType, userId, 0, Binder.getCallingUid());
- }
-
ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags,
int filterCallingUid) {
synchronized (mService) {
@@ -1330,9 +1326,19 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
|| (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) {
modifiedFlags |= PackageManager.MATCH_INSTANT;
}
- return mService.getPackageManagerInternalLocked().resolveIntent(
- intent, resolvedType, modifiedFlags, userId, true, filterCallingUid);
+ // In order to allow cross-profile lookup, we clear the calling identity here.
+ // Note the binder identity won't affect the result, but filterCallingUid will.
+
+ // Cross-user/profile call check are done at the entry points
+ // (e.g. AMS.startActivityAsUser).
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return mService.getPackageManagerInternalLocked().resolveIntent(
+ intent, resolvedType, modifiedFlags, userId, true, filterCallingUid);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
} finally {
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -2409,6 +2415,16 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
if (stack.isCompatible(windowingMode, activityType)) {
return stack;
}
+ if (windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY
+ && display.getSplitScreenPrimaryStack() == stack
+ && candidateTask == stack.topTask()) {
+ // This is a special case when we try to launch an activity that is currently on
+ // top of split-screen primary stack, but is targeting split-screen secondary.
+ // In this case we don't want to move it to another stack.
+ // TODO(b/78788972): Remove after differentiating between preferred and required
+ // launch options.
+ return stack;
+ }
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java
index 31ccf3530fb9..5e29d10908ca 100644
--- a/services/core/java/com/android/server/am/ActivityStartController.java
+++ b/services/core/java/com/android/server/am/ActivityStartController.java
@@ -233,7 +233,7 @@ public class ActivityStartController {
* ensures {@code targetUserId} is a real user ID and not a special user ID such as
* {@link android.os.UserHandle#USER_ALL}, etc.
*/
- private int checkTargetUser(int targetUserId, boolean validateIncomingUser,
+ int checkTargetUser(int targetUserId, boolean validateIncomingUser,
int realCallingPid, int realCallingUid, String reason) {
if (validateIncomingUser) {
return mService.mUserController.handleIncomingUser(realCallingPid, realCallingUid,
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index 5b6b50869dda..8c3ff34aa73d 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -203,7 +203,7 @@ class ActivityStartInterceptor {
mResolvedType = null;
final UserInfo parent = mUserManager.getProfileParent(mUserId);
- mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
+ mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0, mRealCallingUid);
mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
return true;
}
@@ -223,9 +223,11 @@ class ActivityStartInterceptor {
final UserInfo parent = mUserManager.getProfileParent(mUserId);
if (parent != null) {
- mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
+ mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0,
+ mRealCallingUid);
} else {
- mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId);
+ mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0,
+ mRealCallingUid);
}
mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
return true;
@@ -244,7 +246,8 @@ class ActivityStartInterceptor {
final Intent moreDetailsIntent = new Intent(Intent.ACTION_SHOW_SUSPENDED_APP_DETAILS)
.setPackage(suspendingPackage);
final String requiredPermission = Manifest.permission.SEND_SHOW_SUSPENDED_APP_DETAILS;
- final ResolveInfo resolvedInfo = mSupervisor.resolveIntent(moreDetailsIntent, null, userId);
+ final ResolveInfo resolvedInfo = mSupervisor.resolveIntent(moreDetailsIntent, null, userId,
+ 0, mRealCallingUid);
if (resolvedInfo != null && resolvedInfo.activityInfo != null
&& requiredPermission.equals(resolvedInfo.activityInfo.permission)) {
moreDetailsIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, suspendedPackage)
@@ -276,7 +279,7 @@ class ActivityStartInterceptor {
mCallingPid = mRealCallingPid;
mCallingUid = mRealCallingUid;
mResolvedType = null;
- mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, 0);
+ mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid);
mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
return true;
}
@@ -309,7 +312,7 @@ class ActivityStartInterceptor {
}
final UserInfo parent = mUserManager.getProfileParent(mUserId);
- mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
+ mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id, 0, mRealCallingUid);
mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
return true;
}
@@ -362,7 +365,7 @@ class ActivityStartInterceptor {
mCallingUid = mRealCallingUid;
mResolvedType = null;
- mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId);
+ mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid);
mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
return true;
}
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 7ff7d9a9b6c4..fb4107cfd221 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -791,7 +791,7 @@ class ActivityStarter {
callingUid = realCallingUid;
callingPid = realCallingPid;
- rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
+ rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, 0, realCallingUid);
aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
null /*profilerInfo*/);
@@ -952,6 +952,9 @@ class ActivityStarter {
mSupervisor.getActivityMetricsLogger().notifyActivityLaunching();
boolean componentSpecified = intent.getComponent() != null;
+ final int realCallingPid = Binder.getCallingPid();
+ final int realCallingUid = Binder.getCallingUid();
+
// Save a copy in case ephemeral needs it
final Intent ephemeralIntent = new Intent(intent);
// Don't modify the client's object!
@@ -969,7 +972,8 @@ class ActivityStarter {
componentSpecified = false;
}
- ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
+ ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
+ 0 /* matchFlags */, realCallingUid);
if (rInfo == null) {
UserInfo userInfo = mSupervisor.getUserInfo(userId);
if (userInfo != null && userInfo.isManagedProfile()) {
@@ -991,7 +995,7 @@ class ActivityStarter {
rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- Binder.getCallingUid());
+ realCallingUid);
}
}
}
@@ -999,8 +1003,6 @@ class ActivityStarter {
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
synchronized (mService) {
- final int realCallingPid = Binder.getCallingPid();
- final int realCallingUid = Binder.getCallingUid();
int callingPid;
if (callingUid >= 0) {
callingPid = -1;
@@ -1073,7 +1075,8 @@ class ActivityStarter {
callingUid = Binder.getCallingUid();
callingPid = Binder.getCallingPid();
componentSpecified = true;
- rInfo = mSupervisor.resolveIntent(intent, null /*resolvedType*/, userId);
+ rInfo = mSupervisor.resolveIntent(intent, null /*resolvedType*/, userId,
+ 0 /* matchFlags */, realCallingUid);
aInfo = rInfo != null ? rInfo.activityInfo : null;
if (aInfo != null) {
aInfo = mService.getActivityInfoForUser(aInfo, userId);
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
index f4278196b576..ac745985417e 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.net.ConnectivityMetricsEvent;
import android.net.IIpConnectivityMetrics;
import android.net.INetdEventCallback;
+import android.net.ip.IpClient;
import android.net.metrics.ApfProgramEvent;
import android.net.metrics.IpConnectivityLog;
import android.os.Binder;
@@ -269,10 +270,12 @@ final public class IpConnectivityMetrics extends SystemService {
// Dump the rolling buffer of metrics event and pretty print events using a human readable
// format. Also print network dns/connect statistics and default network event time series.
static final String CMD_LIST = "list";
- // By default any other argument will fall into the default case which is remapped to the
- // "list" command. This includes most notably bug reports collected by dumpsys.cpp with
- // the "-a" argument.
- static final String CMD_DEFAULT = CMD_LIST;
+ // Dump all IpClient logs ("ipclient").
+ static final String CMD_IPCLIENT = IpClient.DUMP_ARG;
+ // By default any other argument will fall into the default case which is the equivalent
+ // of calling both the "list" and "ipclient" commands. This includes most notably bug
+ // reports collected by dumpsys.cpp with the "-a" argument.
+ static final String CMD_DEFAULT = "";
@Override
public int logEvent(ConnectivityMetricsEvent event) {
@@ -292,9 +295,20 @@ final public class IpConnectivityMetrics extends SystemService {
case CMD_PROTO:
cmdListAsProto(pw);
return;
- case CMD_LIST: // fallthrough
+ case CMD_IPCLIENT: {
+ final String[] ipclientArgs = ((args != null) && (args.length > 1))
+ ? Arrays.copyOfRange(args, 1, args.length)
+ : null;
+ IpClient.dumpAllLogs(pw, ipclientArgs);
+ return;
+ }
+ case CMD_LIST:
+ cmdList(pw);
+ return;
default:
cmdList(pw);
+ pw.println("");
+ IpClient.dumpAllLogs(pw, null);
return;
}
}
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index e840a29d0937..03d8f395e36e 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -1279,7 +1279,9 @@ public final class ContentService extends IContentService.Stub {
case Process.SYSTEM_UID:
break; // Okay
default:
- throw new SecurityException("Invalid extras specified.");
+ final String msg = "Invalid extras specified.";
+ Log.w(TAG, msg + " requestsync -f/-F needs to run on 'adb shell'");
+ throw new SecurityException(msg);
}
}
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index a55870f41571..5fa42457ac2f 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -68,6 +68,7 @@ import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
@@ -454,6 +455,7 @@ public class SyncManager {
}
};
+ private final HandlerThread mThread;
private final SyncHandler mSyncHandler;
private final SyncManagerConstants mConstants;
@@ -604,7 +606,9 @@ public class SyncManager {
mSyncAdapters = new SyncAdaptersCache(mContext);
- mSyncHandler = new SyncHandler(BackgroundThread.get().getLooper());
+ mThread = new HandlerThread("SyncManager", android.os.Process.THREAD_PRIORITY_BACKGROUND);
+ mThread.start();
+ mSyncHandler = new SyncHandler(mThread.getLooper());
mSyncAdapters.setListener(new RegisteredServicesCacheListener<SyncAdapterType>() {
@Override
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index f403953f892d..0425844bd9e3 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -316,7 +316,7 @@ class AutomaticBrightnessController {
return true;
}
- private void resetShortTermModel() {
+ public void resetShortTermModel() {
mBrightnessMapper.clearUserDataPoints();
mShortTermModelValid = true;
mShortTermModelAnchor = -1;
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 46e883c44e95..3b35d025f595 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -774,14 +774,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
brightness = mScreenBrightnessForVr;
}
- boolean setBrightnessToOverride = false;
if (brightness < 0 && mPowerRequest.screenBrightnessOverride > 0) {
brightness = mPowerRequest.screenBrightnessOverride;
- // If there's a screen brightness override, we want to reset the brightness to it
- // whenever the user changes it, to communicate that these changes aren't taking
- // effect. However, for a nicer user experience, we don't do it here, but rather after
- // the temporary brightness has been taken into account.
- setBrightnessToOverride = true;
}
final boolean autoBrightnessEnabledInDoze =
@@ -804,12 +798,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
brightnessIsTemporary = true;
}
- // Reset the brightness to the screen brightness override to communicate to the user that
- // her changes aren't taking effect.
- if (setBrightnessToOverride && !brightnessIsTemporary) {
- putScreenBrightnessSetting(brightness);
- }
-
final boolean autoBrightnessAdjustmentChanged = updateAutoBrightnessAdjustment();
if (autoBrightnessAdjustmentChanged) {
mTemporaryAutoBrightnessAdjustment = Float.NaN;
@@ -1452,6 +1440,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
if (userSwitch) {
// Don't treat user switches as user initiated change.
mCurrentScreenBrightnessSetting = mPendingScreenBrightnessSetting;
+ if (mAutomaticBrightnessController != null) {
+ mAutomaticBrightnessController.resetShortTermModel();
+ }
}
mPendingAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
// We don't bother with a pending variable for VR screen brightness since we just
diff --git a/services/core/java/com/android/server/fingerprint/ClientMonitor.java b/services/core/java/com/android/server/fingerprint/ClientMonitor.java
index 4100a9a5f71c..b935ba2a2ea4 100644
--- a/services/core/java/com/android/server/fingerprint/ClientMonitor.java
+++ b/services/core/java/com/android/server/fingerprint/ClientMonitor.java
@@ -80,7 +80,7 @@ public abstract class ClientMonitor implements IBinder.DeathRecipient {
mGroupId = groupId;
mIsRestricted = restricted;
mOwner = owner;
- mSuccessVibrationEffect = getSuccessVibrationEffect(context);
+ mSuccessVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
mErrorVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
try {
if (token != null) {
@@ -239,25 +239,4 @@ public abstract class ClientMonitor implements IBinder.DeathRecipient {
vibrator.vibrate(mErrorVibrationEffect, FINGERPRINT_SONFICATION_ATTRIBUTES);
}
}
-
- private static VibrationEffect getSuccessVibrationEffect(Context ctx) {
- int[] arr = ctx.getResources().getIntArray(
- com.android.internal.R.array.config_longPressVibePattern);
- final long[] vibePattern;
- if (arr == null || arr.length == 0) {
- vibePattern = DEFAULT_SUCCESS_VIBRATION_PATTERN;
- } else {
- vibePattern = new long[arr.length];
- for (int i = 0; i < arr.length; i++) {
- vibePattern[i] = arr[i];
- }
- }
- if (vibePattern.length == 1) {
- return VibrationEffect.createOneShot(
- vibePattern[0], VibrationEffect.DEFAULT_AMPLITUDE);
- } else {
- return VibrationEffect.createWaveform(vibePattern, -1);
- }
- }
-
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 64750b00368b..4e6307dbca8a 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1887,9 +1887,26 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
GPS_CAPABILITY_MEASUREMENTS));
mGnssNavigationMessageProvider.onCapabilitiesUpdated(hasCapability(
GPS_CAPABILITY_NAV_MESSAGES));
+ restartRequests();
}
});
- }
+ }
+
+ private void restartRequests() {
+ Log.i(TAG, "restartRequests");
+
+ restartLocationRequest();
+ mGnssMeasurementsProvider.resumeIfStarted();
+ mGnssNavigationMessageProvider.resumeIfStarted();
+ mGnssBatchingProvider.resumeIfStarted();
+ mGnssGeofenceProvider.resumeIfStarted();
+ }
+
+ private void restartLocationRequest() {
+ if (DEBUG) Log.d(TAG, "restartLocationRequest");
+ mStarted = false;
+ updateRequirements();
+ }
/**
* Called from native code to inform us the hardware year.
@@ -1909,6 +1926,23 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
mHardwareModelName = modelName;
}
+ /**
+ * Called from native code to inform us GNSS HAL service died.
+ */
+ private void reportGnssServiceDied() {
+ if (DEBUG) Log.d(TAG, "reportGnssServiceDied");
+ mHandler.post(() -> {
+ class_init_native();
+ native_init_once();
+ if (isEnabled()) {
+ // re-calls native_init() and other setup.
+ handleEnable();
+ // resend configuration into the restarted HAL service.
+ reloadGpsProperties(mContext, mProperties);
+ }
+ });
+ }
+
public interface GnssSystemInfoProvider {
/**
* Returns the year of underlying GPS hardware.
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ec3949f9a441..bf177985da70 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
+import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
@@ -710,7 +711,7 @@ public class NotificationManagerService extends SystemService {
StatusBarNotification sbn = r.sbn;
cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
sbn.getId(), Notification.FLAG_AUTO_CANCEL,
- Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
+ FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
REASON_CLICK, nv.rank, nv.count, null);
nv.recycle();
reportUserInteraction(r);
@@ -754,7 +755,7 @@ public class NotificationManagerService extends SystemService {
}
}
cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
- Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
+ Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
true, userId, REASON_CANCEL, nv.rank, nv.count,null);
nv.recycle();
}
@@ -985,7 +986,7 @@ public class NotificationManagerService extends SystemService {
cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
record.sbn.getPackageName(), record.sbn.getTag(),
record.sbn.getId(), 0,
- Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
+ FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
REASON_TIMEOUT, null);
}
}
@@ -2084,7 +2085,7 @@ public class NotificationManagerService extends SystemService {
// Don't allow client applications to cancel foreground service notis or autobundled
// summaries.
final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
- (Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
+ (FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
}
@@ -2099,7 +2100,7 @@ public class NotificationManagerService extends SystemService {
// Calling from user space, don't allow the canceling of actively
// running foreground services.
cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
- pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
+ pkg, null, 0, FLAG_FOREGROUND_SERVICE, true, userId,
REASON_APP_CANCEL_ALL, null);
}
@@ -2685,7 +2686,7 @@ public class NotificationManagerService extends SystemService {
private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
- Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
+ Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
true,
userId, REASON_LISTENER_CANCEL, info);
}
@@ -3876,7 +3877,9 @@ public class NotificationManagerService extends SystemService {
for (int j = 0; j < listenerSize; j++) {
if (i > 0) pw.print(',');
final ManagedServiceInfo listener = listeners.valueAt(i);
- pw.print(listener.component);
+ if (listener != null) {
+ pw.print(listener.component);
+ }
}
}
pw.println(')');
@@ -3962,7 +3965,7 @@ public class NotificationManagerService extends SystemService {
// FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
// initially *and* force remove FLAG_FOREGROUND_SERVICE.
sbn.getNotification().flags =
- (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
+ (r.mOriginalFlags & ~FLAG_FOREGROUND_SERVICE);
mRankingHelper.sort(mNotificationList);
mListeners.notifyPostedLocked(r, r);
}
@@ -4048,17 +4051,29 @@ public class NotificationManagerService extends SystemService {
final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
r.setIsAppImportanceLocked(mRankingHelper.getIsAppImportanceLocked(pkg, callingUid));
- if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0
- && (channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
- && (r.getImportance() == IMPORTANCE_MIN || r.getImportance() == IMPORTANCE_NONE)) {
- // Increase the importance of foreground service notifications unless the user had an
- // opinion otherwise
- if (TextUtils.isEmpty(channelId)
- || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
- r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
- } else {
- channel.setImportance(IMPORTANCE_LOW);
- mRankingHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
+ if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
+ final boolean fgServiceShown = channel.isFgServiceShown();
+ if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
+ || !fgServiceShown)
+ && (r.getImportance() == IMPORTANCE_MIN
+ || r.getImportance() == IMPORTANCE_NONE)) {
+ // Increase the importance of foreground service notifications unless the user had
+ // an opinion otherwise (and the channel hasn't yet shown a fg service).
+ if (TextUtils.isEmpty(channelId)
+ || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
+ r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
+ } else {
+ channel.setImportance(IMPORTANCE_LOW);
+ if (!fgServiceShown) {
+ channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
+ channel.setFgServiceShown(true);
+ }
+ mRankingHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
+ r.updateNotificationChannel(channel);
+ }
+ } else if (!fgServiceShown && !TextUtils.isEmpty(channelId)
+ && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
+ channel.setFgServiceShown(true);
r.updateNotificationChannel(channel);
}
}
@@ -4429,7 +4444,7 @@ public class NotificationManagerService extends SystemService {
mUsageStats.registerUpdatedByApp(r, old);
// Make sure we don't lose the foreground service state.
notification.flags |=
- old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
+ old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
r.isUpdate = true;
r.setInterruptive(isVisuallyInterruptive(old, r));
}
@@ -4438,7 +4453,7 @@ public class NotificationManagerService extends SystemService {
// Ensure if this is a foreground service that the proper additional
// flags are set.
- if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
+ if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {
notification.flags |= Notification.FLAG_ONGOING_EVENT
| Notification.FLAG_NO_CLEAR;
}
@@ -4506,6 +4521,13 @@ public class NotificationManagerService extends SystemService {
if (oldN.extras == null || newN.extras == null) {
return false;
}
+
+ // Ignore visual interruptions from foreground services because users
+ // consider them one 'session'. Count them for everything else.
+ if (r != null && (r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) {
+ return false;
+ }
+
if (!Objects.equals(oldN.extras.get(Notification.EXTRA_TITLE),
newN.extras.get(Notification.EXTRA_TITLE))) {
return true;
@@ -5805,7 +5827,7 @@ public class NotificationManagerService extends SystemService {
final StatusBarNotification childSbn = childR.sbn;
if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
childR.getGroupKey().equals(parentNotification.getGroupKey())
- && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0
+ && (childR.getFlags() & FLAG_FOREGROUND_SERVICE) == 0
&& (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
childSbn.getTag(), userId, 0, 0, reason, listenerName);
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index febce31c2229..7f141eeba839 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -116,17 +116,12 @@ public class RankingHelper implements RankingConfig {
private final ArrayMap<String, Record> mRecords = new ArrayMap<>(); // pkg|uid => Record
private final ArrayMap<String, NotificationRecord> mProxyByGroupTmp = new ArrayMap<>();
private final ArrayMap<String, Record> mRestoredWithoutUids = new ArrayMap<>(); // pkg => Record
- private final ArrayMap<Pair<String, Integer>, Boolean> mSystemAppCache = new ArrayMap<>();
private final Context mContext;
private final RankingHandler mRankingHandler;
private final PackageManager mPm;
private SparseBooleanArray mBadgingEnabled;
- private Signature[] mSystemSignature;
- private String mPermissionControllerPackageName;
- private String mServicesSystemSharedLibPackageName;
- private String mSharedSystemSharedLibPackageName;
private boolean mAreChannelsBypassingDnd;
private ZenModeHelper mZenModeHelper;
@@ -161,7 +156,6 @@ public class RankingHelper implements RankingConfig {
}
}
- getSignatures();
updateChannelsBypassingDnd();
}
@@ -623,7 +617,6 @@ public class RankingHelper implements RankingConfig {
if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channel.getId())) {
throw new IllegalArgumentException("Reserved id");
}
- final boolean isSystemApp = isSystemPackage(pkg, uid);
NotificationChannel existing = r.channels.get(channel.getId());
// Keep most of the existing settings
if (existing != null && fromTargetApp) {
@@ -651,7 +644,7 @@ public class RankingHelper implements RankingConfig {
// system apps and dnd access apps can bypass dnd if the user hasn't changed any
// fields on the channel yet
- if (existing.getUserLockedFields() == 0 && (isSystemApp || hasDndAccess)) {
+ if (existing.getUserLockedFields() == 0 && hasDndAccess) {
boolean bypassDnd = channel.canBypassDnd();
existing.setBypassDnd(bypassDnd);
@@ -669,7 +662,7 @@ public class RankingHelper implements RankingConfig {
}
// Reset fields that apps aren't allowed to set.
- if (fromTargetApp && !(isSystemApp || hasDndAccess)) {
+ if (fromTargetApp && !hasDndAccess) {
channel.setBypassDnd(r.priority == Notification.PRIORITY_MAX);
}
if (fromTargetApp) {
@@ -695,65 +688,6 @@ public class RankingHelper implements RankingConfig {
channel.unlockFields(channel.getUserLockedFields());
}
- /**
- * Determine whether a package is a "system package", in which case certain things (like
- * bypassing DND) should be allowed.
- */
- private boolean isSystemPackage(String pkg, int uid) {
- Pair<String, Integer> app = new Pair(pkg, uid);
- if (mSystemAppCache.containsKey(app)) {
- return mSystemAppCache.get(app);
- }
-
- PackageInfo pi;
- try {
- pi = mPm.getPackageInfoAsUser(
- pkg, PackageManager.GET_SIGNATURES, UserHandle.getUserId(uid));
- } catch (NameNotFoundException e) {
- Slog.w(TAG, "Can't find pkg", e);
- return false;
- }
- boolean isSystem = (mSystemSignature[0] != null
- && mSystemSignature[0].equals(getFirstSignature(pi)))
- || pkg.equals(mPermissionControllerPackageName)
- || pkg.equals(mServicesSystemSharedLibPackageName)
- || pkg.equals(mSharedSystemSharedLibPackageName)
- || pkg.equals(PrintManager.PRINT_SPOOLER_PACKAGE_NAME)
- || isDeviceProvisioningPackage(pkg);
- mSystemAppCache.put(app, isSystem);
- return isSystem;
- }
-
- private Signature getFirstSignature(PackageInfo pkg) {
- if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) {
- return pkg.signatures[0];
- }
- return null;
- }
-
- private Signature getSystemSignature() {
- try {
- final PackageInfo sys = mPm.getPackageInfoAsUser(
- "android", PackageManager.GET_SIGNATURES, UserHandle.USER_SYSTEM);
- return getFirstSignature(sys);
- } catch (NameNotFoundException e) {
- }
- return null;
- }
-
- private boolean isDeviceProvisioningPackage(String packageName) {
- String deviceProvisioningPackage = mContext.getResources().getString(
- com.android.internal.R.string.config_deviceProvisioningPackage);
- return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName);
- }
-
- private void getSignatures() {
- mSystemSignature = new Signature[]{getSystemSignature()};
- mPermissionControllerPackageName = mPm.getPermissionControllerPackageName();
- mServicesSystemSharedLibPackageName = mPm.getServicesSystemSharedLibraryPackageName();
- mSharedSystemSharedLibPackageName = mPm.getSharedSystemSharedLibraryPackageName();
- }
-
@Override
public void updateNotificationChannel(String pkg, int uid, NotificationChannel updatedChannel,
boolean fromUser) {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 156f70259938..658c7f179691 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -173,18 +173,6 @@ public class ZenModeHelper {
}
}
- public boolean shouldSuppressWhenScreenOff() {
- synchronized (mConfig) {
- return !mConfig.allowWhenScreenOff;
- }
- }
-
- public boolean shouldSuppressWhenScreenOn() {
- synchronized (mConfig) {
- return !mConfig.allowWhenScreenOn;
- }
- }
-
public void addCallback(Callback callback) {
mCallbacks.add(callback);
}
@@ -592,14 +580,12 @@ public class ZenModeHelper {
return;
}
pw.printf("allow(alarms=%b,media=%b,system=%b,calls=%b,callsFrom=%s,repeatCallers=%b,"
- + "messages=%b,messagesFrom=%s,"
- + "events=%b,reminders=%b,whenScreenOff=%b,whenScreenOn=%b)\n",
+ + "messages=%b,messagesFrom=%s,events=%b,reminders=%b)\n",
config.allowAlarms, config.allowMedia, config.allowSystem,
config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
config.allowRepeatCallers, config.allowMessages,
ZenModeConfig.sourceToString(config.allowMessagesFrom),
- config.allowEvents, config.allowReminders, config.allowWhenScreenOff,
- config.allowWhenScreenOn);
+ config.allowEvents, config.allowReminders);
pw.printf(" disallow(visualEffects=%s)\n", config.suppressedVisualEffects);
pw.print(prefix); pw.print(" manualRule="); pw.println(config.manualRule);
if (config.automaticRules.isEmpty()) return;
@@ -1185,7 +1171,7 @@ public class ZenModeHelper {
private void showZenUpgradeNotification(int zen) {
final boolean showNotification = mIsBootComplete
- && zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ && zen != Global.ZEN_MODE_OFF
&& Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 0) != 0;
@@ -1204,17 +1190,20 @@ public class ZenModeHelper {
mContext.getResources().getString(R.string.global_action_settings));
int title = R.string.zen_upgrade_notification_title;
int content = R.string.zen_upgrade_notification_content;
+ int drawable = R.drawable.ic_zen_24dp;
if (NotificationManager.Policy.areAllVisualEffectsSuppressed(
getNotificationPolicy().suppressedVisualEffects)) {
title = R.string.zen_upgrade_notification_visd_title;
content = R.string.zen_upgrade_notification_visd_content;
+ drawable = R.drawable.ic_dnd_block_notifications;
}
+
Intent onboardingIntent = new Intent(Settings.ZEN_MODE_ONBOARDING);
onboardingIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
return new Notification.Builder(mContext, SystemNotificationChannels.DO_NOT_DISTURB)
.setAutoCancel(true)
.setSmallIcon(R.drawable.ic_settings_24dp)
- .setLargeIcon(Icon.createWithResource(mContext, R.drawable.ic_zen_24dp))
+ .setLargeIcon(Icon.createWithResource(mContext, drawable))
.setContentTitle(mContext.getResources().getString(title))
.setContentText(mContext.getResources().getString(content))
.setContentIntent(PendingIntent.getActivity(mContext, 0, onboardingIntent,
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 3b8a994c4e87..8562572c3c39 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -389,11 +389,16 @@ public final class OverlayManagerService extends SystemService {
final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
false);
if (pi != null) {
+ /*
+ * Only update overlay settings when an overlay becomes enabled or disabled.
+ * Enabling or disabling components of a target should not change the
+ * target's overlays. Since, overlays do not have components, this will only
+ * update overlay settings if an overlay package becomes enabled or
+ * disabled.
+ */
mPackageManager.cachePackageInfo(packageName, userId, pi);
if (pi.isOverlayPackage()) {
mImpl.onOverlayPackageChanged(packageName, userId);
- } else {
- mImpl.onTargetPackageChanged(packageName, userId);
}
}
}
@@ -694,32 +699,25 @@ public final class OverlayManagerService extends SystemService {
private final class OverlayChangeListener
implements OverlayManagerServiceImpl.OverlayChangeListener {
@Override
- public void onChanged(@NonNull final String targetPackageName, final int userId,
- boolean targetChanged, boolean overlayChanged) {
+ public void onOverlaysChanged(@NonNull final String targetPackageName, final int userId) {
schedulePersistSettings();
FgThread.getHandler().post(() -> {
- // Update the targets' overlays if a change to the target or an overlay occurs
- if (targetChanged || overlayChanged) {
- updateAssets(userId, targetPackageName);
- }
+ updateAssets(userId, targetPackageName);
- // Create the broadcast if the overlay changes
- if (overlayChanged) {
- final Intent intent = new Intent(Intent.ACTION_OVERLAY_CHANGED,
- Uri.fromParts("package", targetPackageName, null));
- intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ final Intent intent = new Intent(Intent.ACTION_OVERLAY_CHANGED,
+ Uri.fromParts("package", targetPackageName, null));
+ intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- if (DEBUG) {
- Slog.d(TAG, "send broadcast " + intent);
- }
+ if (DEBUG) {
+ Slog.d(TAG, "send broadcast " + intent);
+ }
- try {
- ActivityManager.getService().broadcastIntent(null, intent, null, null, 0,
- null, null, null, android.app.AppOpsManager.OP_NONE, null, false,
- false, userId);
- } catch (RemoteException e) {
- // Intentionally left empty.
- }
+ try {
+ ActivityManager.getService().broadcastIntent(null, intent, null, null, 0,
+ null, null, null, android.app.AppOpsManager.OP_NONE, null, false, false,
+ userId);
+ } catch (RemoteException e) {
+ // Intentionally left empty.
}
});
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index a487ae970821..bb36ab189765 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -207,15 +207,9 @@ final class OverlayManagerServiceImpl {
Slog.d(TAG, "onTargetPackageAdded packageName=" + packageName + " userId=" + userId);
}
- updateAllOverlaysForTarget(packageName, userId, 0);
- }
-
- void onTargetPackageChanged(@NonNull final String packageName, final int userId) {
- if (DEBUG) {
- Slog.d(TAG, "onTargetPackageChanged packageName=" + packageName + " userId=" + userId);
+ if (updateAllOverlaysForTarget(packageName, userId, 0)) {
+ mListener.onOverlaysChanged(packageName, userId);
}
-
- updateAllOverlaysForTarget(packageName, userId, 0);
}
void onTargetPackageUpgrading(@NonNull final String packageName, final int userId) {
@@ -224,7 +218,9 @@ final class OverlayManagerServiceImpl {
+ userId);
}
- updateAllOverlaysForTarget(packageName, userId, FLAG_TARGET_IS_UPGRADING);
+ if (updateAllOverlaysForTarget(packageName, userId, FLAG_TARGET_IS_UPGRADING)) {
+ mListener.onOverlaysChanged(packageName, userId);
+ }
}
void onTargetPackageUpgraded(@NonNull final String packageName, final int userId) {
@@ -232,7 +228,9 @@ final class OverlayManagerServiceImpl {
Slog.d(TAG, "onTargetPackageUpgraded packageName=" + packageName + " userId=" + userId);
}
- updateAllOverlaysForTarget(packageName, userId, 0);
+ if (updateAllOverlaysForTarget(packageName, userId, 0)) {
+ mListener.onOverlaysChanged(packageName, userId);
+ }
}
void onTargetPackageRemoved(@NonNull final String packageName, final int userId) {
@@ -240,17 +238,21 @@ final class OverlayManagerServiceImpl {
Slog.d(TAG, "onTargetPackageRemoved packageName=" + packageName + " userId=" + userId);
}
- updateAllOverlaysForTarget(packageName, userId, 0);
+ if (updateAllOverlaysForTarget(packageName, userId, 0)) {
+ mListener.onOverlaysChanged(packageName, userId);
+ }
}
/**
- * Calls OverlayChangeListener#onChanged if the settings for the overlay target were modified,
- * and calls OverlayChangeListener#onTargetChanged to signal a change in the target package that
- * requires updating target overlays.
+ * Update the state of any overlays for this target.
+ *
+ * Returns true if the system should refresh the app's overlay paths (i.e.
+ * if the settings were modified for this target, or there is at least one
+ * enabled framework overlay).
*/
- private void updateAllOverlaysForTarget(@NonNull final String targetPackageName,
+ private boolean updateAllOverlaysForTarget(@NonNull final String targetPackageName,
final int userId, final int flags) {
- boolean overlayModified = false;
+ boolean modified = false;
final List<OverlayInfo> ois = mSettings.getOverlaysForTarget(targetPackageName, userId);
final int N = ois.size();
for (int i = 0; i < N; i++) {
@@ -258,19 +260,22 @@ final class OverlayManagerServiceImpl {
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(oi.packageName,
userId);
if (overlayPackage == null) {
- overlayModified |= mSettings.remove(oi.packageName, oi.userId);
+ modified |= mSettings.remove(oi.packageName, oi.userId);
removeIdmapIfPossible(oi);
} else {
try {
- overlayModified |= updateState(targetPackageName, oi.packageName, userId, flags);
+ modified |= updateState(targetPackageName, oi.packageName, userId, flags);
} catch (OverlayManagerSettings.BadKeyException e) {
Slog.e(TAG, "failed to update settings", e);
- overlayModified |= mSettings.remove(oi.packageName, userId);
+ modified |= mSettings.remove(oi.packageName, userId);
}
}
}
- mListener.onChanged(targetPackageName, userId, /* targetChanged */ true, overlayModified);
+ // check for enabled framework overlays
+ modified = modified || !getEnabledOverlayPackageNames("android", userId).isEmpty();
+
+ return modified;
}
void onOverlayPackageAdded(@NonNull final String packageName, final int userId) {
@@ -291,8 +296,7 @@ final class OverlayManagerServiceImpl {
overlayPackage.overlayCategory);
try {
if (updateState(overlayPackage.overlayTarget, packageName, userId, 0)) {
- mListener.onChanged(overlayPackage.overlayTarget, userId,
- /* targetChanged */ false, /* overlayChanged */ true);
+ mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
}
} catch (OverlayManagerSettings.BadKeyException e) {
Slog.e(TAG, "failed to update settings", e);
@@ -308,8 +312,7 @@ final class OverlayManagerServiceImpl {
try {
final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
if (updateState(oi.targetPackageName, packageName, userId, 0)) {
- mListener.onChanged(oi.targetPackageName, userId,
- /* targetChanged */ false, /* overlayChanged */ true);
+ mListener.onOverlaysChanged(oi.targetPackageName, userId);
}
} catch (OverlayManagerSettings.BadKeyException e) {
Slog.e(TAG, "failed to update settings", e);
@@ -326,8 +329,7 @@ final class OverlayManagerServiceImpl {
final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
if (updateState(oi.targetPackageName, packageName, userId, FLAG_OVERLAY_IS_UPGRADING)) {
removeIdmapIfPossible(oi);
- mListener.onChanged(oi.targetPackageName, userId,
- /* targetChanged */ false, /* overlayChanged */ true);
+ mListener.onOverlaysChanged(oi.targetPackageName, userId);
}
} catch (OverlayManagerSettings.BadKeyException e) {
Slog.e(TAG, "failed to update settings", e);
@@ -361,8 +363,7 @@ final class OverlayManagerServiceImpl {
}
if (updateState(pkg.overlayTarget, packageName, userId, 0)) {
- mListener.onChanged(pkg.overlayTarget, userId,
- /* targetChanged */ false, /* overlayChanged */ true);
+ mListener.onOverlaysChanged(pkg.overlayTarget, userId);
}
} catch (OverlayManagerSettings.BadKeyException e) {
Slog.e(TAG, "failed to update settings", e);
@@ -376,8 +377,7 @@ final class OverlayManagerServiceImpl {
removeIdmapIfPossible(overlayInfo);
if (overlayInfo.isEnabled()) {
// Only trigger updates if the overlay was enabled.
- mListener.onChanged(overlayInfo.targetPackageName, userId,
- /* targetChanged */ false, /* overlayChanged */ true);
+ mListener.onOverlaysChanged(overlayInfo.targetPackageName, userId);
}
}
} catch (OverlayManagerSettings.BadKeyException e) {
@@ -425,8 +425,7 @@ final class OverlayManagerServiceImpl {
modified |= updateState(oi.targetPackageName, oi.packageName, userId, 0);
if (modified) {
- mListener.onChanged(oi.targetPackageName, userId,
- /* targetChanged */ false, /* overlayChanged */ true);
+ mListener.onOverlaysChanged(oi.targetPackageName, userId);
}
return true;
} catch (OverlayManagerSettings.BadKeyException e) {
@@ -485,8 +484,7 @@ final class OverlayManagerServiceImpl {
modified |= updateState(targetPackageName, packageName, userId, 0);
if (modified) {
- mListener.onChanged(targetPackageName, userId,
- /* targetChanged */ false, /* overlayChanged */ true);
+ mListener.onOverlaysChanged(targetPackageName, userId);
}
return true;
} catch (OverlayManagerSettings.BadKeyException e) {
@@ -519,8 +517,7 @@ final class OverlayManagerServiceImpl {
}
if (mSettings.setPriority(packageName, newParentPackageName, userId)) {
- mListener.onChanged(overlayPackage.overlayTarget, userId,
- /* targetChanged */ false, /* overlayChanged */ true);
+ mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
}
return true;
}
@@ -540,8 +537,7 @@ final class OverlayManagerServiceImpl {
}
if (mSettings.setHighestPriority(packageName, userId)) {
- mListener.onChanged(overlayPackage.overlayTarget, userId,
- /* targetChanged */ false, /* overlayChanged */ true);
+ mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
}
return true;
}
@@ -561,8 +557,7 @@ final class OverlayManagerServiceImpl {
}
if (mSettings.setLowestPriority(packageName, userId)) {
- mListener.onChanged(overlayPackage.overlayTarget, userId,
- /* targetChanged */ false, /* overlayChanged */ true);
+ mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
}
return true;
}
@@ -693,8 +688,7 @@ final class OverlayManagerServiceImpl {
}
interface OverlayChangeListener {
- void onChanged(@NonNull String targetPackage, int userId,
- boolean targetChanged, boolean overlayChanged);
+ void onOverlaysChanged(@NonNull String targetPackage, int userId);
}
interface PackageManagerHelper {
diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java
index dbf0940fb4f5..d0a3757be04d 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolver.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolver.java
@@ -16,6 +16,8 @@
package com.android.server.pm;
+import static android.content.Intent.FLAG_ACTIVITY_MATCH_EXTERNAL;
+
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_INSTANT_APP_RESOLUTION_PHASE_ONE;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_INSTANT_APP_RESOLUTION_PHASE_TWO;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_INSTANT_APP_LAUNCH_TOKEN;
@@ -366,6 +368,7 @@ public abstract class InstantAppResolver {
final Intent failureIntent = new Intent(origIntent);
boolean requiresSecondPhase = false;
failureIntent.setFlags(failureIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL);
+ failureIntent.setFlags(failureIntent.getFlags() & ~Intent.FLAG_ACTIVITY_MATCH_EXTERNAL);
failureIntent.setLaunchToken(token);
ArrayList<AuxiliaryResolveInfo.AuxiliaryFilter> filters = null;
boolean isWebIntent = origIntent.isWebIntent();
@@ -408,6 +411,10 @@ public abstract class InstantAppResolver {
if (filters != null && !filters.isEmpty()) {
return new AuxiliaryResolveInfo(token, requiresSecondPhase, failureIntent, filters);
}
+ // if the match external flag is set, return an empty resolve info
+ if ((origIntent.getFlags() & FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) {
+ return new AuxiliaryResolveInfo(token, false, failureIntent, null /* filters */);
+ }
// Hash or filter mis-match; no instant apps for this domain.
return null;
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 595de9e35a7f..feac8e6a4509 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -21,6 +21,7 @@ import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
+import android.app.IApplicationThread;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -560,7 +561,7 @@ public class LauncherAppsService extends SystemService {
}
@Override
- public void startActivityAsUser(String callingPackage,
+ public void startActivityAsUser(IApplicationThread caller, String callingPackage,
ComponentName component, Rect sourceBounds,
Bundle opts, UserHandle user) throws RemoteException {
if (!canAccessProfile(user.getIdentifier(), "Cannot start activity")) {
@@ -574,6 +575,8 @@ public class LauncherAppsService extends SystemService {
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
launchIntent.setPackage(component.getPackageName());
+ boolean canLaunch = false;
+
final int callingUid = injectBinderCallingUid();
long ident = Binder.clearCallingIdentity();
try {
@@ -604,35 +607,42 @@ public class LauncherAppsService extends SystemService {
// this component so ok to launch.
launchIntent.setPackage(null);
launchIntent.setComponent(component);
- mContext.startActivityAsUser(launchIntent, opts, user);
- return;
+ canLaunch = true;
+ break;
}
}
- throw new SecurityException("Attempt to launch activity without "
- + " category Intent.CATEGORY_LAUNCHER " + component);
+ if (!canLaunch) {
+ throw new SecurityException("Attempt to launch activity without "
+ + " category Intent.CATEGORY_LAUNCHER " + component);
+ }
} finally {
Binder.restoreCallingIdentity(ident);
}
+ mActivityManagerInternal.startActivityAsUser(caller, callingPackage,
+ launchIntent, opts, user.getIdentifier());
}
@Override
- public void showAppDetailsAsUser(String callingPackage, ComponentName component,
+ public void showAppDetailsAsUser(IApplicationThread caller,
+ String callingPackage, ComponentName component,
Rect sourceBounds, Bundle opts, UserHandle user) throws RemoteException {
if (!canAccessProfile(user.getIdentifier(), "Cannot show app details")) {
return;
}
+ final Intent intent;
long ident = Binder.clearCallingIdentity();
try {
String packageName = component.getPackageName();
- Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
+ intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", packageName, null));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.setSourceBounds(sourceBounds);
- mContext.startActivityAsUser(intent, opts, user);
} finally {
Binder.restoreCallingIdentity(ident);
}
+ mActivityManagerInternal.startActivityAsUser(caller, callingPackage,
+ intent, opts, user.getIdentifier());
}
/** Checks if user is a profile of or same as listeningUser.
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 05b3809b41ab..af5521d036af 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -8429,7 +8429,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Delete invalid userdata apps
if ((scanFlags & SCAN_AS_SYSTEM) == 0 &&
- errorCode == PackageManager.INSTALL_FAILED_INVALID_APK) {
+ errorCode != PackageManager.INSTALL_SUCCEEDED) {
logCriticalInfo(Log.WARN,
"Deleting invalid package at " + parseResult.scanFile);
removeCodePathLI(parseResult.scanFile);
@@ -22446,9 +22446,13 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
final String volumeUuid = pkg.volumeUuid;
final String packageName = pkg.packageName;
- final ApplicationInfo app = (ps == null)
+
+ ApplicationInfo app = (ps == null)
? pkg.applicationInfo
: PackageParser.generateApplicationInfo(pkg, 0, ps.readUserState(userId), userId);
+ if (app == null) {
+ app = pkg.applicationInfo;
+ }
final int appId = UserHandle.getAppId(app.uid);
diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java
index 96c102b50a12..045a295da965 100644
--- a/services/core/java/com/android/server/pm/UserDataPreparer.java
+++ b/services/core/java/com/android/server/pm/UserDataPreparer.java
@@ -24,6 +24,8 @@ import android.os.Environment;
import android.os.FileUtils;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
+import android.os.SystemProperties;
+import android.os.UserHandle;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -96,6 +98,14 @@ class UserDataPreparer {
}
mInstaller.createUserData(volumeUuid, userId, userSerial, flags);
+
+ // CE storage is available after they are prepared.
+ if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 &&
+ (userId == UserHandle.USER_SYSTEM)) {
+ String propertyName = "sys.user." + userId + ".ce_available";
+ Slog.d(TAG, "Setting property: " + propertyName + "=true");
+ SystemProperties.set(propertyName, "true");
+ }
} catch (Exception e) {
logCriticalInfo(Log.WARN, "Destroying user " + userId + " on volume " + volumeUuid
+ " because we failed to prepare: " + e);
@@ -103,7 +113,8 @@ class UserDataPreparer {
if (allowRecover) {
// Try one last time; if we fail again we're really in trouble
- prepareUserDataLI(volumeUuid, userId, userSerial, flags, false);
+ prepareUserDataLI(volumeUuid, userId, userSerial,
+ flags | StorageManager.FLAG_STORAGE_DE, false);
}
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 1d5b1a38bbee..18f3434ece49 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -234,6 +234,7 @@ import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.DisplayCutout;
+import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.IApplicationToken;
@@ -7191,14 +7192,35 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
@Override
- public boolean isDockSideAllowed(int dockSide) {
+ public boolean isDockSideAllowed(int dockSide, int originalDockSide, int displayWidth,
+ int displayHeight, int displayRotation) {
+ final int barPosition = navigationBarPosition(displayWidth, displayHeight, displayRotation);
+ return isDockSideAllowed(dockSide, originalDockSide, barPosition, mNavigationBarCanMove);
+ }
- // We do not allow all dock sides at which the navigation bar touches the docked stack.
- if (!mNavigationBarCanMove) {
- return dockSide == DOCKED_TOP || dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT;
- } else {
- return dockSide == DOCKED_TOP || dockSide == DOCKED_LEFT;
+ @VisibleForTesting
+ static boolean isDockSideAllowed(int dockSide, int originalDockSide,
+ int navBarPosition, boolean navigationBarCanMove) {
+ if (dockSide == DOCKED_TOP) {
+ return true;
+ }
+
+ if (navigationBarCanMove) {
+ // Only allow the dockside opposite to the nav bar position in landscape
+ return dockSide == DOCKED_LEFT && navBarPosition == NAV_BAR_RIGHT
+ || dockSide == DOCKED_RIGHT && navBarPosition == NAV_BAR_LEFT;
}
+
+ // Side is the same as original side
+ if (dockSide == originalDockSide) {
+ return true;
+ }
+
+ // Only if original docked side was top in portrait will allow left for landscape
+ if (dockSide == DOCKED_LEFT && originalDockSide == DOCKED_TOP) {
+ return true;
+ }
+ return false;
}
void sendCloseSystemWindows() {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index ccbf502bc2b5..8690a8392961 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -1706,11 +1706,19 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
DisplayCutout displayCutout, Rect outInsets);
/**
+ * @param displayRotation the current display rotation
+ * @param displayWidth the current display width
+ * @param displayHeight the current display height
+ * @param dockSide the dockside asking if allowed
+ * @param originalDockSide the side that was original docked to in split screen
* @return True if a specified {@param dockSide} is allowed on the current device, or false
* otherwise. It is guaranteed that at least one dock side for a particular orientation
* is allowed, so for example, if DOCKED_RIGHT is not allowed, DOCKED_LEFT is allowed.
+ * If navigation bar is movable then the docked side would bias towards the
+ * {@param originalDockSide}.
*/
- public boolean isDockSideAllowed(int dockSide);
+ public boolean isDockSideAllowed(int dockSide, int originalDockSide, int displayWidth,
+ int displayHeight, int displayRotation);
/**
* Called when the configuration has changed, and it's safe to load new values from resources.
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 20283a792cfb..a492672f0ea5 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -719,13 +719,14 @@ final class Notifier {
* Plays the wireless charging sound for both wireless and non-wireless charging
*/
private void playChargingStartedSound() {
- // TODO (b/77912907): add back charging sound enabled check & default to charging sounds ON
+ final boolean enabled = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.CHARGING_SOUNDS_ENABLED, 1) != 0;
final boolean dndOff = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
== Settings.Global.ZEN_MODE_OFF;
final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
Settings.Global.CHARGING_STARTED_SOUND);
- if (dndOff && soundPath != null) {
+ if (enabled && dndOff && soundPath != null) {
final Uri soundUri = Uri.parse("file://" + soundPath);
if (soundUri != null) {
final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index c5275333b184..cb84cf3fa72b 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -90,6 +90,16 @@ public class BatterySaverController implements BatterySaverPolicyListener {
*/
private final Plugin[] mPlugins;
+ public static final int REASON_AUTOMATIC_ON = 0;
+ public static final int REASON_AUTOMATIC_OFF = 1;
+ public static final int REASON_MANUAL_ON = 2;
+ public static final int REASON_MANUAL_OFF = 3;
+ public static final int REASON_STICKY_RESTORE = 4;
+ public static final int REASON_INTERACTIVE_CHANGED = 5;
+ public static final int REASON_POLICY_CHANGED = 6;
+ public static final int REASON_PLUGGED_IN = 7;
+ public static final int REASON_SETTING_CHANGED = 8;
+
/**
* Plugin interface. All methods are guaranteed to be called on the same (handler) thread.
*/
@@ -113,7 +123,8 @@ public class BatterySaverController implements BatterySaverPolicyListener {
return; // No need to send it if not enabled.
}
// Don't send the broadcast, because we never did so in this case.
- mHandler.postStateChanged(/*sendBroadcast=*/ false);
+ mHandler.postStateChanged(/*sendBroadcast=*/ false,
+ REASON_INTERACTIVE_CHANGED);
break;
case Intent.ACTION_BATTERY_CHANGED:
synchronized (mLock) {
@@ -184,7 +195,7 @@ public class BatterySaverController implements BatterySaverPolicyListener {
if (!isEnabled()) {
return; // No need to send it if not enabled.
}
- mHandler.postStateChanged(/*sendBroadcast=*/ true);
+ mHandler.postStateChanged(/*sendBroadcast=*/ true, REASON_POLICY_CHANGED);
}
private class MyHandler extends Handler {
@@ -199,9 +210,9 @@ public class BatterySaverController implements BatterySaverPolicyListener {
super(looper);
}
- public void postStateChanged(boolean sendBroadcast) {
+ public void postStateChanged(boolean sendBroadcast, int reason) {
obtainMessage(MSG_STATE_CHANGED, sendBroadcast ?
- ARG_SEND_BROADCAST : ARG_DONT_SEND_BROADCAST, 0).sendToTarget();
+ ARG_SEND_BROADCAST : ARG_DONT_SEND_BROADCAST, reason).sendToTarget();
}
public void postSystemReady() {
@@ -212,7 +223,9 @@ public class BatterySaverController implements BatterySaverPolicyListener {
public void dispatchMessage(Message msg) {
switch (msg.what) {
case MSG_STATE_CHANGED:
- handleBatterySaverStateChanged(msg.arg1 == ARG_SEND_BROADCAST);
+ handleBatterySaverStateChanged(
+ msg.arg1 == ARG_SEND_BROADCAST,
+ msg.arg2);
break;
case MSG_SYSTEM_READY:
@@ -227,14 +240,14 @@ public class BatterySaverController implements BatterySaverPolicyListener {
/**
* Called by {@link PowerManagerService} to update the battery saver stete.
*/
- public void enableBatterySaver(boolean enable) {
+ public void enableBatterySaver(boolean enable, int reason) {
synchronized (mLock) {
if (mEnabled == enable) {
return;
}
mEnabled = enable;
- mHandler.postStateChanged(/*sendBroadcast=*/ true);
+ mHandler.postStateChanged(/*sendBroadcast=*/ true, reason);
}
}
@@ -275,7 +288,7 @@ public class BatterySaverController implements BatterySaverPolicyListener {
* - When battery saver is on the interactive state changes.
* - When battery saver is on the battery saver policy changes.
*/
- void handleBatterySaverStateChanged(boolean sendBroadcast) {
+ void handleBatterySaverStateChanged(boolean sendBroadcast, int reason) {
final LowPowerModeListener[] listeners;
final boolean enabled;
@@ -287,7 +300,8 @@ public class BatterySaverController implements BatterySaverPolicyListener {
mPreviouslyEnabled ? 1 : 0, // Previously off or on.
mEnabled ? 1 : 0, // Now off or on.
isInteractive ? 1 : 0, // Device interactive state.
- mEnabled ? mBatterySaverPolicy.toEventLogString() : "");
+ mEnabled ? mBatterySaverPolicy.toEventLogString() : "",
+ reason);
mPreviouslyEnabled = mEnabled;
listeners = mListeners.toArray(new LowPowerModeListener[mListeners.size()]);
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index 28605215e19d..b9f31b126f0b 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -18,6 +18,7 @@ package com.android.server.power.batterysaver;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
+import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Global;
@@ -27,6 +28,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
+import com.android.server.EventLogTags;
import com.android.server.power.BatterySaverPolicy;
import com.android.server.power.BatterySaverStateMachineProto;
@@ -95,6 +97,18 @@ public class BatterySaverStateMachine {
@GuardedBy("mLock")
private boolean mBatterySaverSnoozing;
+ /**
+ * Last reason passed to {@link #enableBatterySaverLocked}.
+ */
+ @GuardedBy("mLock")
+ private int mLastChangedIntReason;
+
+ /**
+ * Last reason passed to {@link #enableBatterySaverLocked}.
+ */
+ @GuardedBy("mLock")
+ private String mLastChangedStrReason;
+
private final ContentObserver mSettingsObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
@@ -149,11 +163,25 @@ public class BatterySaverStateMachine {
});
}
+ /**
+ * Run a {@link Runnable} on a background handler.
+ */
@VisibleForTesting
void runOnBgThread(Runnable r) {
BackgroundThread.getHandler().post(r);
}
+ /**
+ * Run a {@link Runnable} on a background handler, but lazily. If the same {@link Runnable},
+ * it'll be first removed before a new one is posted.
+ */
+ @VisibleForTesting
+ void runOnBgThreadLazy(Runnable r, int delayMillis) {
+ final Handler h = BackgroundThread.getHandler();
+ h.removeCallbacks(r);
+ h.postDelayed(r, delayMillis);
+ }
+
void refreshSettingsLocked() {
final ContentResolver cr = mContext.getContentResolver();
@@ -199,14 +227,23 @@ public class BatterySaverStateMachine {
mSettingBatterySaverEnabledSticky = batterySaverEnabledSticky;
mSettingBatterySaverTriggerThreshold = batterySaverTriggerThreshold;
+ if (thresholdChanged) {
+ // To avoid spamming the event log, we throttle logging here.
+ runOnBgThreadLazy(mThresholdChangeLogger, 2000);
+ }
+
if (enabledChanged) {
final String reason = batterySaverEnabled
? "Global.low_power changed to 1" : "Global.low_power changed to 0";
enableBatterySaverLocked(/*enable=*/ batterySaverEnabled, /*manual=*/ true,
- reason);
+ BatterySaverController.REASON_SETTING_CHANGED, reason);
}
}
+ private final Runnable mThresholdChangeLogger = () -> {
+ EventLogTags.writeBatterySaverSetting(mSettingBatterySaverTriggerThreshold);
+ };
+
/**
* {@link com.android.server.power.PowerManagerService} calls it when battery state changes.
*
@@ -257,18 +294,26 @@ public class BatterySaverStateMachine {
}
if (mIsPowered) {
updateSnoozingLocked(false, "Plugged in");
- enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false, "Plugged in");
+ enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false,
+ BatterySaverController.REASON_PLUGGED_IN,
+ "Plugged in");
} else if (mSettingBatterySaverEnabledSticky) {
// Re-enable BS.
- enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ true, "Sticky restore");
+ enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ true,
+ BatterySaverController.REASON_STICKY_RESTORE,
+ "Sticky restore");
} else if (mIsBatteryLevelLow) {
if (!mBatterySaverSnoozing && isAutoBatterySaverConfigured()) {
- enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false, "Auto ON");
+ enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false,
+ BatterySaverController.REASON_AUTOMATIC_ON,
+ "Auto ON");
}
} else { // Battery not low
- enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false, "Auto OFF");
+ enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false,
+ BatterySaverController.REASON_AUTOMATIC_OFF,
+ "Auto OFF");
}
}
@@ -284,6 +329,8 @@ public class BatterySaverStateMachine {
}
synchronized (mLock) {
enableBatterySaverLocked(/*enable=*/ enabled, /*manual=*/ true,
+ (enabled ? BatterySaverController.REASON_MANUAL_ON
+ : BatterySaverController.REASON_MANUAL_OFF),
(enabled ? "Manual ON" : "Manual OFF"));
}
}
@@ -292,10 +339,11 @@ public class BatterySaverStateMachine {
* Actually enable / disable battery saver. Write the new state to the global settings
* and propagate it to {@link #mBatterySaverController}.
*/
- private void enableBatterySaverLocked(boolean enable, boolean manual, String reason) {
+ private void enableBatterySaverLocked(boolean enable, boolean manual, int intReason,
+ String strReason) {
if (DEBUG) {
Slog.d(TAG, "enableBatterySaver: enable=" + enable + " manual=" + manual
- + " reason=" + reason);
+ + " reason=" + strReason + "(" + intReason + ")");
}
final boolean wasEnabled = mBatterySaverController.isEnabled();
@@ -309,6 +357,8 @@ public class BatterySaverStateMachine {
if (DEBUG) Slog.d(TAG, "Can't enable: isPowered");
return;
}
+ mLastChangedIntReason = intReason;
+ mLastChangedStrReason = strReason;
if (manual) {
if (enable) {
@@ -330,12 +380,12 @@ public class BatterySaverStateMachine {
mSettingBatterySaverEnabledSticky = enable;
putGlobalSetting(Global.LOW_POWER_MODE_STICKY, enable ? 1 : 0);
}
- mBatterySaverController.enableBatterySaver(enable);
+ mBatterySaverController.enableBatterySaver(enable, intReason);
if (DEBUG) {
Slog.d(TAG, "Battery saver: Enabled=" + enable
+ " manual=" + manual
- + " reason=" + reason);
+ + " reason=" + strReason + "(" + intReason + ")");
}
}
@@ -365,6 +415,11 @@ public class BatterySaverStateMachine {
pw.print(" Enabled=");
pw.println(mBatterySaverController.isEnabled());
+ pw.print(" mLastChangedIntReason=");
+ pw.println(mLastChangedIntReason);
+ pw.print(" mLastChangedStrReason=");
+ pw.println(mLastChangedStrReason);
+
pw.print(" mBootCompleted=");
pw.println(mBootCompleted);
pw.print(" mSettingsLoaded=");
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index 165a409028d6..644e3c3c732b 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -671,6 +671,17 @@ public class AppWindowContainerController
}
}
+ public void notifyAppStopping() {
+ synchronized(mWindowMap) {
+ if (mContainer == null) {
+ Slog.w(TAG_WM, "Attempted to notify stopping on non-existing app token: "
+ + mToken);
+ return;
+ }
+ mContainer.detachChildren();
+ }
+ }
+
public void notifyAppStopped() {
synchronized(mWindowMap) {
if (mContainer == null) {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index a9560e65db09..966ca4104710 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -913,12 +913,16 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
// try and clean up it's child surfaces. We need to prevent this from
// happening, so we sever the children, transfering their ownership
// from the client it-self to the parent surface (owned by us).
+ detachChildren();
+
+ mPendingRelaunchCount++;
+ }
+
+ void detachChildren() {
for (int i = mChildren.size() - 1; i >= 0; i--) {
final WindowState w = mChildren.get(i);
w.mWinAnimator.detachChildren();
}
-
- mPendingRelaunchCount++;
}
void finishRelaunching() {
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 2cd2ef1203cb..c8baced4cd5d 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -170,7 +170,7 @@ public class DockedStackDividerController {
final int orientation = mTmpRect2.width() <= mTmpRect2.height()
? ORIENTATION_PORTRAIT
: ORIENTATION_LANDSCAPE;
- final int dockSide = TaskStack.getDockSideUnchecked(mTmpRect, mTmpRect2, orientation);
+ final int dockSide = getDockSide(mTmpRect, mTmpRect2, orientation);
final int position = DockedDividerUtils.calculatePositionForBounds(mTmpRect, dockSide,
getContentWidth());
@@ -191,6 +191,39 @@ public class DockedStackDividerController {
return (int) (minWidth / mDisplayContent.getDisplayMetrics().density);
}
+ /**
+ * Get the current docked side. Determined by its location of {@param bounds} within
+ * {@param displayRect} but if both are the same, it will try to dock to each side and determine
+ * if allowed in its respected {@param orientation}.
+ *
+ * @param bounds bounds of the docked task to get which side is docked
+ * @param displayRect bounds of the display that contains the docked task
+ * @param orientation the origination of device
+ * @return current docked side
+ */
+ int getDockSide(Rect bounds, Rect displayRect, int orientation) {
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ // Portrait mode, docked either at the top or the bottom.
+ final int diff = (displayRect.bottom - bounds.bottom) - (bounds.top - displayRect.top);
+ if (diff > 0) {
+ return DOCKED_TOP;
+ } else if (diff < 0) {
+ return DOCKED_BOTTOM;
+ }
+ return canPrimaryStackDockTo(DOCKED_TOP) ? DOCKED_TOP : DOCKED_BOTTOM;
+ } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ // Landscape mode, docked either on the left or on the right.
+ final int diff = (displayRect.right - bounds.right) - (bounds.left - displayRect.left);
+ if (diff > 0) {
+ return DOCKED_LEFT;
+ } else if (diff < 0) {
+ return DOCKED_RIGHT;
+ }
+ return canPrimaryStackDockTo(DOCKED_LEFT) ? DOCKED_LEFT : DOCKED_RIGHT;
+ }
+ return DOCKED_INVALID;
+ }
+
void getHomeStackBoundsInDockedMode(Rect outBounds) {
final DisplayInfo di = mDisplayContent.getDisplayInfo();
mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
@@ -203,10 +236,20 @@ public class DockedStackDividerController {
outBounds.set(0, mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top,
di.logicalWidth, di.logicalHeight);
} else {
- // In landscape append the left position with the statusbar height to match the
+ // In landscape also inset the left/right side with the statusbar height to match the
// minimized size height in portrait mode.
- outBounds.set(mTaskHeightInMinimizedMode + dividerSize + mTmpRect.left + mTmpRect.top,
- 0, di.logicalWidth, di.logicalHeight);
+ final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
+ final int primaryTaskWidth = mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top;
+ int left = mTmpRect.left;
+ int right = di.logicalWidth - mTmpRect.right;
+ if (stack != null) {
+ if (stack.getDockSide() == DOCKED_LEFT) {
+ left += primaryTaskWidth;
+ } else if (stack.getDockSide() == DOCKED_RIGHT) {
+ right -= primaryTaskWidth;
+ }
+ }
+ outBounds.set(left, 0, right, di.logicalHeight);
}
}
@@ -420,21 +463,9 @@ public class DockedStackDividerController {
* @return true if the side provided is valid
*/
boolean canPrimaryStackDockTo(int dockSide) {
- if (mService.mPolicy.isDockSideAllowed(dockSide)) {
- // Side is the same as original side
- if (dockSide == mOriginalDockedSide) {
- return true;
- }
- // Special rule that the top in portrait is always valid
- if (dockSide == DOCKED_TOP) {
- return true;
- }
- // Only if original docked side was top in portrait will allow left side for landscape
- if (dockSide == DOCKED_LEFT && mOriginalDockedSide == DOCKED_TOP) {
- return true;
- }
- }
- return false;
+ final DisplayInfo di = mDisplayContent.getDisplayInfo();
+ return mService.mPolicy.isDockSideAllowed(dockSide, mOriginalDockedSide, di.logicalWidth,
+ di.logicalHeight, di.rotation);
}
void notifyDockedStackExistsChanged(boolean exists) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 6b13edd072cd..efc4e737b92c 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -317,7 +317,7 @@ class TaskSnapshotController {
@VisibleForTesting
int getSnapshotMode(Task task) {
final AppWindowToken topChild = task.getTopChild();
- if (!task.isActivityTypeStandardOrUndefined()) {
+ if (!task.isActivityTypeStandardOrUndefined() && !task.isActivityTypeAssistant()) {
return SNAPSHOT_MODE_NONE;
} else if (topChild != null && topChild.shouldUseAppThemeSnapshot()) {
return SNAPSHOT_MODE_APP_THEME;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 018765d1ecdc..891ee2e55f47 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1462,27 +1462,7 @@ public class TaskStack extends WindowContainer<Task> implements
}
dc.getBounds(mTmpRect);
final int orientation = dc.getConfiguration().orientation;
- return getDockSideUnchecked(bounds, mTmpRect, orientation);
- }
-
- static int getDockSideUnchecked(Rect bounds, Rect displayRect, int orientation) {
- if (orientation == Configuration.ORIENTATION_PORTRAIT) {
- // Portrait mode, docked either at the top or the bottom.
- if (bounds.top - displayRect.top <= displayRect.bottom - bounds.bottom) {
- return DOCKED_TOP;
- } else {
- return DOCKED_BOTTOM;
- }
- } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
- // Landscape mode, docked either on the left or on the right.
- if (bounds.left - displayRect.left <= displayRect.right - bounds.right) {
- return DOCKED_LEFT;
- } else {
- return DOCKED_RIGHT;
- }
- } else {
- return DOCKED_INVALID;
- }
+ return dc.getDockedDividerController().getDockSide(bounds, mTmpRect, orientation);
}
boolean hasTaskForUser(int userId) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index a3428f0bb50e..4a6587bcc8af 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1287,6 +1287,12 @@ class WindowStateAnimator {
if (!shown)
return false;
+ // If we had a preserved surface it's no longer needed, and it may be harmful
+ // if we are transparent.
+ if (mPendingDestroySurface != null && mDestroyPreservedSurfaceUponRedraw) {
+ mPendingDestroySurface.mSurfaceControl.hide();
+ }
+
return true;
}
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index a3a7e1e7d1b2..288f3509b393 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -64,6 +64,7 @@ static jmethodID method_reportGeofenceResumeStatus;
static jmethodID method_reportMeasurementData;
static jmethodID method_reportNavigationMessages;
static jmethodID method_reportLocationBatch;
+static jmethodID method_reportGnssServiceDied;
/*
* Save a pointer to JavaVm to attach/detach threads executing
@@ -120,10 +121,10 @@ struct GnssDeathRecipient : virtual public hidl_death_recipient
{
// hidl_death_recipient interface
virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override {
- // TODO(b/37460011): implement a better death recovery mechanism without
- // crashing system server process as described in go//treble-gnss-death
- LOG_ALWAYS_FATAL("Abort due to IGNSS hidl service failure,"
- " restarting system server");
+ ALOGE("IGNSS hidl service failed, trying to recover...");
+
+ JNIEnv* env = android::AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(mCallbacksObj, method_reportGnssServiceDied);
}
};
@@ -1177,6 +1178,7 @@ static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass
clazz,
"reportLocationBatch",
"([Landroid/location/Location;)V");
+ method_reportGnssServiceDied = env->GetMethodID(clazz, "reportGnssServiceDied", "()V");
/*
* Save a pointer to JVM.
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 94f8f38739bc..ab93a8a91fb9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3944,6 +3944,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (metrics.quality != quality) {
metrics.quality = quality;
updatePasswordValidityCheckpointLocked(userId, parent);
+ saveSettingsLocked(userId);
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
@@ -4055,6 +4056,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (metrics.length != length) {
metrics.length = length;
updatePasswordValidityCheckpointLocked(userId, parent);
+ saveSettingsLocked(userId);
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
@@ -4079,6 +4081,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (ap.passwordHistoryLength != length) {
ap.passwordHistoryLength = length;
updatePasswordValidityCheckpointLocked(userId, parent);
+ saveSettingsLocked(userId);
}
}
if (SecurityLog.isLoggingEnabled()) {
@@ -4280,6 +4283,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (metrics.upperCase != length) {
metrics.upperCase = length;
updatePasswordValidityCheckpointLocked(userId, parent);
+ saveSettingsLocked(userId);
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
@@ -4302,6 +4306,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (metrics.lowerCase != length) {
metrics.lowerCase = length;
updatePasswordValidityCheckpointLocked(userId, parent);
+ saveSettingsLocked(userId);
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
@@ -4327,6 +4332,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (metrics.letters != length) {
metrics.letters = length;
updatePasswordValidityCheckpointLocked(userId, parent);
+ saveSettingsLocked(userId);
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
@@ -4352,6 +4358,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (metrics.numeric != length) {
metrics.numeric = length;
updatePasswordValidityCheckpointLocked(userId, parent);
+ saveSettingsLocked(userId);
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
@@ -4377,6 +4384,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (metrics.symbols != length) {
ap.minimumPasswordMetrics.symbols = length;
updatePasswordValidityCheckpointLocked(userId, parent);
+ saveSettingsLocked(userId);
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
@@ -4402,6 +4410,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (metrics.nonLetter != length) {
ap.minimumPasswordMetrics.nonLetter = length;
updatePasswordValidityCheckpointLocked(userId, parent);
+ saveSettingsLocked(userId);
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
@@ -6087,6 +6096,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
synchronized (getLockObject()) {
policy.mFailedPasswordAttempts = 0;
updatePasswordValidityCheckpointLocked(userId, /* parent */ false);
+ saveSettingsLocked(userId);
updatePasswordExpirationsLocked(userId);
setExpirationAlarmCheckLocked(mContext, userId, /* parent */ false);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 74b40ba23518..1880e9fa362c 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -156,6 +156,9 @@ public final class SystemServer {
// give any timezone code room without going into negative time.
private static final long EARLIEST_SUPPORTED_TIME = 86400 * 1000;
+ private static final long SLOW_DISPATCH_THRESHOLD_MS = 100;
+ private static final long SLOW_DELIVERY_THRESHOLD_MS = 200;
+
/*
* Implementation class names. TODO: Move them to a codegen class or load
* them from the build system somehow.
@@ -396,6 +399,8 @@ public final class SystemServer {
android.os.Process.THREAD_PRIORITY_FOREGROUND);
android.os.Process.setCanSelfBackground(false);
Looper.prepareMainLooper();
+ Looper.getMainLooper().setSlowLogThresholdMs(
+ SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
// Initialize native services.
System.loadLibrary("android_servers");
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index d6999ddf07f6..63ae09a79379 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -54,6 +54,7 @@ import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.R;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.IState;
import com.android.internal.util.Preconditions;
@@ -74,6 +75,7 @@ import java.util.Objects;
import java.util.List;
import java.util.Set;
import java.util.StringJoiner;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -100,6 +102,36 @@ public class IpClient extends StateMachine {
private static final Class[] sMessageClasses = { IpClient.class, DhcpClient.class };
private static final SparseArray<String> sWhatToString =
MessageUtils.findMessageNames(sMessageClasses);
+ // Two static concurrent hashmaps of interface name to logging classes.
+ // One holds StateMachine logs and the other connectivity packet logs.
+ private static final ConcurrentHashMap<String, SharedLog> sSmLogs = new ConcurrentHashMap<>();
+ private static final ConcurrentHashMap<String, LocalLog> sPktLogs = new ConcurrentHashMap<>();
+
+ // If |args| is non-empty, assume it's a list of interface names for which
+ // we should print IpClient logs (filter out all others).
+ public static void dumpAllLogs(PrintWriter writer, String[] args) {
+ for (String ifname : sSmLogs.keySet()) {
+ if (!ArrayUtils.isEmpty(args) && !ArrayUtils.contains(args, ifname)) continue;
+
+ writer.println(String.format("--- BEGIN %s ---", ifname));
+
+ final SharedLog smLog = sSmLogs.get(ifname);
+ if (smLog != null) {
+ writer.println("State machine log:");
+ smLog.dump(null, writer, null);
+ }
+
+ writer.println("");
+
+ final LocalLog pktLog = sPktLogs.get(ifname);
+ if (pktLog != null) {
+ writer.println("Connectivity packet log:");
+ pktLog.readOnlyLocalLog().dump(null, writer, null);
+ }
+
+ writer.println(String.format("--- END %s ---", ifname));
+ }
+ }
/**
* Callbacks for handling IpClient events.
@@ -680,8 +712,10 @@ public class IpClient extends StateMachine {
mShutdownLatch = new CountDownLatch(1);
mNwService = deps.getNMS();
- mLog = new SharedLog(MAX_LOG_RECORDS, mTag);
- mConnectivityPacketLog = new LocalLog(MAX_PACKET_RECORDS);
+ sSmLogs.putIfAbsent(mInterfaceName, new SharedLog(MAX_LOG_RECORDS, mTag));
+ mLog = sSmLogs.get(mInterfaceName);
+ sPktLogs.putIfAbsent(mInterfaceName, new LocalLog(MAX_PACKET_RECORDS));
+ mConnectivityPacketLog = sPktLogs.get(mInterfaceName);
mMsgStateLogger = new MessageHandlingLogger();
// TODO: Consider creating, constructing, and passing in some kind of
diff --git a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
index 949c504d64dc..b1dad5a87957 100644
--- a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
+++ b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
@@ -419,7 +419,7 @@ public class PerformBackupTaskTest {
runTask(task);
verify(mObserver).onResult(PACKAGE_1, BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
- verify(mObserver).backupFinished(BackupManager.ERROR_TRANSPORT_ABORTED);
+ verify(mObserver).backupFinished(BackupManager.SUCCESS);
}
@Test
@@ -467,8 +467,7 @@ public class PerformBackupTaskTest {
verify(mObserver).onResult(PACKAGE_1, BackupManager.SUCCESS);
verify(mObserver).onResult(PACKAGE_2, BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
- // TODO: Should we return the status of the last?
- verify(mObserver).backupFinished(BackupManager.ERROR_TRANSPORT_ABORTED);
+ verify(mObserver).backupFinished(BackupManager.SUCCESS);
}
@Test
@@ -488,7 +487,7 @@ public class PerformBackupTaskTest {
runTask(task);
verify(mObserver).onResult(PACKAGE_1, BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
- verify(mObserver).backupFinished(BackupManager.ERROR_TRANSPORT_ABORTED);
+ verify(mObserver).backupFinished(BackupManager.SUCCESS);
verify(agentMock.agent).onQuotaExceeded(anyLong(), anyLong());
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
index 9daea1afc505..1415ada5fc92 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
@@ -19,51 +19,44 @@ package com.android.server.am;
import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
+
import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
+import static com.android.server.am.ActivityStackSupervisor
+ .MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
+
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
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 static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.ArgumentMatchers.any;
-
-import android.app.ActivityManager;
+import android.app.ActivityOptions;
import android.app.WaitResult;
-import android.content.ComponentName;
-import android.content.res.Configuration;
import android.graphics.Rect;
-import android.hardware.display.DisplayManager;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.SparseIntArray;
-import org.junit.runner.RunWith;
import org.junit.Before;
import org.junit.Test;
-
+import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
/**
* Tests for the {@link ActivityStackSupervisor} class.
@@ -378,4 +371,28 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase {
assertEquals(showWhenLockedActivity, mService.mStackSupervisor.topRunningActivityLocked(
true /* considerKeyguardState */));
}
+
+ /**
+ * Verify that split-screen primary stack will be chosen if activity is launched that targets
+ * split-screen secondary, but a matching existing instance is found on top of split-screen
+ * primary stack.
+ */
+ @Test
+ public void testSplitScreenPrimaryChosenWhenTopActivityLaunchedToSecondary() throws Exception {
+ // Create primary split-screen stack with a task and an activity.
+ final ActivityStack primaryStack = mService.mStackSupervisor.getDefaultDisplay()
+ .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
+ true /* onTop */);
+ final TaskRecord task = new TaskBuilder(mSupervisor).setStack(primaryStack).build();
+ final ActivityRecord r = new ActivityBuilder(mService).setTask(task).build();
+
+ // Find a launch stack for the top activity in split-screen primary, while requesting
+ // split-screen secondary.
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
+ final ActivityStack result = mSupervisor.getLaunchStack(r, options, task, true /* onTop */);
+
+ // Assert that the primary stack is returned.
+ assertEquals(primaryStack, result);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index b76064b7ebdf..1acecfc8cb05 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4259,7 +4259,14 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// Drain ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED broadcasts as part of
// reportPasswordChanged()
- verify(mContext.spiedContext, times(3)).sendBroadcastAsUser(
+ // This broadcast should be sent 4 times:
+ // * Twice from calls to DevicePolicyManagerService.updatePasswordExpirationsLocked,
+ // once for each affected user, in DevicePolicyManagerService.reportPasswordChanged.
+ // * Twice from calls to DevicePolicyManagerService.saveSettingsLocked
+ // in DevicePolicyManagerService.reportPasswordChanged, once with the userId
+ // the password change is relevant to and another with the credential owner of said
+ // userId.
+ verify(mContext.spiedContext, times(4)).sendBroadcastAsUser(
MockUtils.checkIntentAction(
DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
MockUtils.checkUserHandle(userHandle));
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index e2ba4d5f4aa8..213961c1e1d9 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -254,6 +254,12 @@ public class DpmMockContext extends MockContext {
}
@Override
+ public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
+ String[] receiverPermissions) {
+ spiedContext.sendBroadcastAsUserMultiplePermissions(intent, user, receiverPermissions);
+ }
+
+ @Override
public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
spiedContext.sendBroadcast(intent, receiverPermission, options);
}
diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTest.java
index 64637f4c5ffe..30665b56c8dc 100644
--- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTest.java
@@ -28,12 +28,19 @@ import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+import static android.view.WindowManager.DOCKED_TOP;
+import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import android.graphics.PixelFormat;
import android.platform.test.annotations.Presubmit;
@@ -194,4 +201,53 @@ public class PhoneWindowManagerTest {
PhoneWindowManager.updateLightNavigationBarLw(0, opaqueDarkNavBar,
opaqueDarkNavBar, imeDrawLightNavBar, imeDrawLightNavBar));
}
+
+ @Test
+ public void testIsDockSideAllowedDockTop() throws Exception {
+ // Docked top is always allowed
+ assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_TOP, DOCKED_LEFT, NAV_BAR_BOTTOM,
+ true /* navigationBarCanMove */));
+ assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_TOP, DOCKED_LEFT, NAV_BAR_BOTTOM,
+ false /* navigationBarCanMove */));
+ }
+
+ @Test
+ public void testIsDockSideAllowedDockBottom() throws Exception {
+ // Cannot dock bottom
+ assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_BOTTOM, DOCKED_LEFT, NAV_BAR_BOTTOM,
+ true /* navigationBarCanMove */));
+ }
+
+ @Test
+ public void testIsDockSideAllowedNavigationBarMovable() throws Exception {
+ assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, NAV_BAR_BOTTOM,
+ true /* navigationBarCanMove */));
+ assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, NAV_BAR_LEFT,
+ true /* navigationBarCanMove */));
+ assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, NAV_BAR_RIGHT,
+ true /* navigationBarCanMove */));
+ assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT, NAV_BAR_BOTTOM,
+ true /* navigationBarCanMove */));
+ assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT, NAV_BAR_RIGHT,
+ true /* navigationBarCanMove */));
+ assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT, NAV_BAR_LEFT,
+ true /* navigationBarCanMove */));
+ }
+
+ @Test
+ public void testIsDockSideAllowedNavigationBarNotMovable() throws Exception {
+ // Navigation bar is not movable such as tablets
+ assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, NAV_BAR_BOTTOM,
+ false /* navigationBarCanMove */));
+ assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_TOP, NAV_BAR_BOTTOM,
+ false /* navigationBarCanMove */));
+ assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_RIGHT, NAV_BAR_BOTTOM,
+ false /* navigationBarCanMove */));
+ assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT, NAV_BAR_BOTTOM,
+ false /* navigationBarCanMove */));
+ assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_TOP, NAV_BAR_BOTTOM,
+ false /* navigationBarCanMove */));
+ assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_RIGHT, NAV_BAR_BOTTOM,
+ false /* navigationBarCanMove */));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
index 1367f583ba38..62fe6b261715 100644
--- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
@@ -17,6 +17,7 @@ package com.android.server.power.batterysaver;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -144,6 +145,11 @@ public class BatterySaverStateMachineTest {
void runOnBgThread(Runnable r) {
r.run();
}
+
+ @Override
+ void runOnBgThreadLazy(Runnable r, int delayMillis) {
+ r.run();
+ }
}
@Before
@@ -153,7 +159,7 @@ public class BatterySaverStateMachineTest {
mMockBatterySaverController = mock(BatterySaverController.class);
doAnswer((inv) -> mDevice.batterySaverEnabled = inv.getArgument(0))
- .when(mMockBatterySaverController).enableBatterySaver(anyBoolean());
+ .when(mMockBatterySaverController).enableBatterySaver(anyBoolean(), anyInt());
when(mMockBatterySaverController.isEnabled())
.thenAnswer((inv) -> mDevice.batterySaverEnabled);
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 c2a0ccfbb810..dee25569705b 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -46,6 +46,7 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import android.app.usage.UsageEvents;
+import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.ContextWrapper;
@@ -74,6 +75,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Unit test for AppStandbyController.
@@ -101,6 +104,8 @@ public class AppStandbyControllerTests {
private static final long WORKING_SET_THRESHOLD = 12 * HOUR_MS;
private static final long FREQUENT_THRESHOLD = 24 * HOUR_MS;
private static final long RARE_THRESHOLD = 48 * HOUR_MS;
+ // Short STABLE_CHARGING_THRESHOLD for testing purposes
+ private static final long STABLE_CHARGING_THRESHOLD = 2000;
private MyInjector mInjector;
private AppStandbyController mController;
@@ -209,7 +214,8 @@ public class AppStandbyControllerTests {
return "screen_thresholds=0/0/0/" + HOUR_MS + ",elapsed_thresholds=0/"
+ WORKING_SET_THRESHOLD + "/"
+ FREQUENT_THRESHOLD + "/"
- + RARE_THRESHOLD;
+ + RARE_THRESHOLD + ","
+ + "stable_charging_threshold=" + STABLE_CHARGING_THRESHOLD;
}
// Internal methods
@@ -276,6 +282,10 @@ public class AppStandbyControllerTests {
return controller;
}
+ private long getCurrentTime() {
+ return TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
+ }
+
@Before
public void setUp() throws Exception {
MyContextWrapper myContext = new MyContextWrapper(InstrumentationRegistry.getContext());
@@ -284,21 +294,101 @@ public class AppStandbyControllerTests {
setChargingState(mController, false);
}
+ private class TestParoleListener extends UsageStatsManagerInternal.AppIdleStateChangeListener {
+ private boolean mOnParole = false;
+ private CountDownLatch mLatch;
+ private long mLastParoleChangeTime;
+
+ public boolean getParoleState() {
+ synchronized (this) {
+ return mOnParole;
+ }
+ }
+
+ public void rearmLatch() {
+ synchronized (this) {
+ mLatch = new CountDownLatch(1);
+ }
+ }
+
+ public void awaitOnLatch(long time) throws Exception {
+ mLatch.await(time, TimeUnit.MILLISECONDS);
+ }
+
+ public long getLastParoleChangeTime() {
+ synchronized (this) {
+ return mLastParoleChangeTime;
+ }
+ }
+
+ @Override
+ public void onAppIdleStateChanged(String packageName, int userId, boolean idle,
+ int bucket, int reason) {
+ }
+
+ @Override
+ public void onParoleStateChanged(boolean isParoleOn) {
+ synchronized (this) {
+ // Only record information if it is being looked for
+ if (mLatch.getCount() > 0) {
+ mOnParole = isParoleOn;
+ mLastParoleChangeTime = getCurrentTime();
+ mLatch.countDown();
+ }
+ }
+ }
+ }
+
@Test
public void testCharging() throws Exception {
+ long startTime;
+ TestParoleListener paroleListener = new TestParoleListener();
+ long marginOfError = 200;
+
+ // Charging
+ paroleListener.rearmLatch();
+ mController.addListener(paroleListener);
+ startTime = getCurrentTime();
setChargingState(mController, true);
- mInjector.mElapsedRealtime = RARE_THRESHOLD + 1;
- assertFalse(mController.isAppIdleFilteredOrParoled(PACKAGE_1, USER_ID,
- mInjector.mElapsedRealtime, false));
-
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertTrue(paroleListener.mOnParole);
+ // Parole will only be granted after device has been charging for a sufficient amount of
+ // time.
+ assertEquals(STABLE_CHARGING_THRESHOLD,
+ paroleListener.getLastParoleChangeTime() - startTime,
+ marginOfError);
+
+ // Discharging
+ paroleListener.rearmLatch();
+ startTime = getCurrentTime();
setChargingState(mController, false);
- mInjector.mElapsedRealtime = 2 * RARE_THRESHOLD + 2;
mController.checkIdleStates(USER_ID);
- assertTrue(mController.isAppIdleFilteredOrParoled(PACKAGE_1, USER_ID,
- mInjector.mElapsedRealtime, false));
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertFalse(paroleListener.getParoleState());
+ // Parole should be revoked immediately
+ assertEquals(0,
+ paroleListener.getLastParoleChangeTime() - startTime,
+ marginOfError);
+
+ // Brief Charging
+ paroleListener.rearmLatch();
+ setChargingState(mController, true);
+ setChargingState(mController, false);
+ // Device stopped charging before the stable charging threshold.
+ // Parole should not be granted at the end of the threshold
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertFalse(paroleListener.getParoleState());
+
+ // Charging Again
+ paroleListener.rearmLatch();
+ startTime = getCurrentTime();
setChargingState(mController, true);
- assertFalse(mController.isAppIdleFilteredOrParoled(PACKAGE_1,USER_ID,
- mInjector.mElapsedRealtime, false));
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertTrue(paroleListener.getParoleState());
+ assertTrue(paroleListener.mOnParole);
+ assertEquals(STABLE_CHARGING_THRESHOLD,
+ paroleListener.getLastParoleChangeTime() - startTime,
+ marginOfError);
}
private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket) {
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 1c2d53899af4..013c67255248 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -552,7 +552,8 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
}
@Override
- public boolean isDockSideAllowed(int dockSide) {
+ public boolean isDockSideAllowed(int dockSide, int originalDockSide, int displayWidth,
+ int displayHeight, int displayRotation) {
return false;
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index eb1c9975cb7e..376cc645fabc 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
+import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
import static android.app.NotificationManager.EXTRA_BLOCKED_STATE;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;
@@ -528,7 +529,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
PKG, new ParceledListSlice(Arrays.asList(channel)));
final StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
- sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
@@ -556,11 +557,34 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertEquals(IMPORTANCE_NONE,
mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
- final StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
- sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
+ sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
+ mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ sbn.getId(), sbn.getNotification(), sbn.getUserId());
+ waitForIdle();
+ // The first time a foreground service notification is shown, we allow the channel
+ // to be updated to allow it to be seen.
+ assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
+ assertEquals(IMPORTANCE_LOW,
+ mService.getNotificationRecord(sbn.getKey()).getImportance());
+ assertEquals(IMPORTANCE_LOW,
+ mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
+ mBinderService.cancelNotificationWithTag(PKG, "tag", sbn.getId(), sbn.getUserId());
+ waitForIdle();
+
+ update = new NotificationChannel("blockedbyuser", "name", IMPORTANCE_NONE);
+ update.setFgServiceShown(true);
+ mBinderService.updateNotificationChannelForPackage(PKG, mUid, update);
+ waitForIdle();
+ assertEquals(IMPORTANCE_NONE,
+ mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
+
+ sbn = generateNotificationRecord(channel).sbn;
+ sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
+ // The second time it is shown, we keep the user's preference.
assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
assertNull(mService.getNotificationRecord(sbn.getKey()));
assertEquals(IMPORTANCE_NONE,
@@ -601,7 +625,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
- sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
@@ -759,7 +783,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testCancelAllNotifications_IgnoreForegroundService() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
- sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
@@ -773,7 +797,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testCancelAllNotifications_IgnoreOtherPackages() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
- sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId());
@@ -901,7 +925,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
- sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mInternalService.removeForegroundServiceFlagFromNotification(PKG, sbn.getId(),
@@ -909,14 +933,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
waitForIdle();
StatusBarNotification[] notifs =
mBinderService.getActiveNotifications(sbn.getPackageName());
- assertEquals(0, notifs[0].getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE);
+ assertEquals(0, notifs[0].getNotification().flags & FLAG_FOREGROUND_SERVICE);
}
@Test
public void testCancelAfterSecondEnqueueDoesNotSpecifyForegroundFlag() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags =
- Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE;
+ Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT;
@@ -937,7 +961,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mTestNotificationChannel, 2, "group", false);
final NotificationRecord child2 = generateNotificationRecord(
mTestNotificationChannel, 3, "group", false);
- child2.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
final NotificationRecord newGroup = generateNotificationRecord(
mTestNotificationChannel, 4, "group2", false);
mService.addNotification(parent);
@@ -960,7 +984,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mTestNotificationChannel, 2, "group", false);
final NotificationRecord child2 = generateNotificationRecord(
mTestNotificationChannel, 3, "group", false);
- child2.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
final NotificationRecord newGroup = generateNotificationRecord(
mTestNotificationChannel, 4, "group2", false);
mService.addNotification(parent);
@@ -984,7 +1008,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mTestNotificationChannel, 2, "group", false);
final NotificationRecord child2 = generateNotificationRecord(
mTestNotificationChannel, 3, "group", false);
- child2.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
final NotificationRecord newGroup = generateNotificationRecord(
mTestNotificationChannel, 4, "group2", false);
mService.addNotification(parent);
@@ -2187,7 +2211,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testReadPolicyXml_readApprovedServicesFromXml() throws Exception {
final String upgradeXml = "<notification-policy version=\"1\">"
- + "<zen></zen>"
+ "<ranking></ranking>"
+ "<enabled_listeners>"
+ "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />"
@@ -2215,7 +2238,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testReadPolicyXml_readApprovedServicesFromSettings() throws Exception {
final String preupgradeXml = "<notification-policy version=\"1\">"
- + "<zen></zen>"
+ "<ranking></ranking>"
+ "</notification-policy>";
mService.readPolicyXml(
@@ -2257,7 +2279,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
NotificationChannel.DEFAULT_CHANNEL_ID)
.setContentTitle("foo")
.setSmallIcon(android.R.drawable.sym_def_app_icon)
- .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+ .setFlag(FLAG_FOREGROUND_SERVICE, true)
.setPriority(Notification.PRIORITY_MIN);
StatusBarNotification sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", preOUid,
@@ -2272,7 +2294,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
nb = new Notification.Builder(mContext)
.setContentTitle("foo")
.setSmallIcon(android.R.drawable.sym_def_app_icon)
- .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+ .setFlag(FLAG_FOREGROUND_SERVICE, true)
.setPriority(Notification.PRIORITY_MIN);
sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", preOUid,
@@ -2670,6 +2692,26 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testVisualDifference_foreground() {
+ Notification.Builder nb1 = new Notification.Builder(mContext, "")
+ .setContentTitle("foo");
+ StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+ nb1.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord r1 =
+ new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
+
+ Notification.Builder nb2 = new Notification.Builder(mContext, "")
+ .setFlag(FLAG_FOREGROUND_SERVICE, true)
+ .setContentTitle("bar");
+ StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+ nb2.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord r2 =
+ new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
+
+ assertFalse(mService.isVisuallyInterruptive(r1, r2));
+ }
+
+ @Test
public void testVisualDifference_diffTitle() {
Notification.Builder nb1 = new Notification.Builder(mContext, "")
.setContentTitle("foo");
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
index d846d213c5b6..36ec2210942d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
@@ -336,6 +336,90 @@ public class NotificationTest extends UiServiceTestCase {
}
@Test
+ public void testRemoteViews_layoutChange() {
+ RemoteViews a = mock(RemoteViews.class);
+ when(a.getLayoutId()).thenReturn(234);
+ RemoteViews b = mock(RemoteViews.class);
+ when(b.getLayoutId()).thenReturn(189);
+
+ Notification.Builder n1 = new Notification.Builder(mContext, "test").setContent(a);
+ Notification.Builder n2 = new Notification.Builder(mContext, "test").setContent(b);
+ assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+
+ n1 = new Notification.Builder(mContext, "test").setCustomBigContentView(a);
+ n2 = new Notification.Builder(mContext, "test").setCustomBigContentView(b);
+ assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+
+ n1 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(a);
+ n2 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(b);
+ assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+ }
+
+ @Test
+ public void testRemoteViews_layoutSame() {
+ RemoteViews a = mock(RemoteViews.class);
+ when(a.getLayoutId()).thenReturn(234);
+ RemoteViews b = mock(RemoteViews.class);
+ when(b.getLayoutId()).thenReturn(234);
+
+ Notification.Builder n1 = new Notification.Builder(mContext, "test").setContent(a);
+ Notification.Builder n2 = new Notification.Builder(mContext, "test").setContent(b);
+ assertFalse(Notification.areRemoteViewsChanged(n1, n2));
+
+ n1 = new Notification.Builder(mContext, "test").setCustomBigContentView(a);
+ n2 = new Notification.Builder(mContext, "test").setCustomBigContentView(b);
+ assertFalse(Notification.areRemoteViewsChanged(n1, n2));
+
+ n1 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(a);
+ n2 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(b);
+ assertFalse(Notification.areRemoteViewsChanged(n1, n2));
+ }
+
+ @Test
+ public void testRemoteViews_sequenceChange() {
+ RemoteViews a = mock(RemoteViews.class);
+ when(a.getLayoutId()).thenReturn(234);
+ when(a.getSequenceNumber()).thenReturn(1);
+ RemoteViews b = mock(RemoteViews.class);
+ when(b.getLayoutId()).thenReturn(234);
+ when(b.getSequenceNumber()).thenReturn(2);
+
+ Notification.Builder n1 = new Notification.Builder(mContext, "test").setContent(a);
+ Notification.Builder n2 = new Notification.Builder(mContext, "test").setContent(b);
+ assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+
+ n1 = new Notification.Builder(mContext, "test").setCustomBigContentView(a);
+ n2 = new Notification.Builder(mContext, "test").setCustomBigContentView(b);
+ assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+
+ n1 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(a);
+ n2 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(b);
+ assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+ }
+
+ @Test
+ public void testRemoteViews_sequenceSame() {
+ RemoteViews a = mock(RemoteViews.class);
+ when(a.getLayoutId()).thenReturn(234);
+ when(a.getSequenceNumber()).thenReturn(1);
+ RemoteViews b = mock(RemoteViews.class);
+ when(b.getLayoutId()).thenReturn(234);
+ when(b.getSequenceNumber()).thenReturn(1);
+
+ Notification.Builder n1 = new Notification.Builder(mContext, "test").setContent(a);
+ Notification.Builder n2 = new Notification.Builder(mContext, "test").setContent(b);
+ assertFalse(Notification.areRemoteViewsChanged(n1, n2));
+
+ n1 = new Notification.Builder(mContext, "test").setCustomBigContentView(a);
+ n2 = new Notification.Builder(mContext, "test").setCustomBigContentView(b);
+ assertFalse(Notification.areRemoteViewsChanged(n1, n2));
+
+ n1 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(a);
+ n2 = new Notification.Builder(mContext, "test").setCustomHeadsUpContentView(b);
+ assertFalse(Notification.areRemoteViewsChanged(n1, n2));
+ }
+
+ @Test
public void testActionsDifferent_null() {
Notification n1 = new Notification.Builder(mContext, "test")
.build();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
index 8183a7467277..890595045ae2 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -1714,13 +1714,13 @@ public class RankingHelperTest extends UiServiceTestCase {
}
@Test
- public void testAndroidPkgCanBypassDnd_creation() {
+ public void testAndroidPkgCannotBypassDnd_creation() {
NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
test.setBypassDnd(true);
mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true, false);
- assertTrue(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false)
+ assertFalse(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false)
.canBypassDnd());
}
@@ -1745,7 +1745,7 @@ public class RankingHelperTest extends UiServiceTestCase {
}
@Test
- public void testAndroidPkgCanBypassDnd_update() throws Exception {
+ public void testAndroidPkgCannotBypassDnd_update() throws Exception {
NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true, false);
@@ -1753,11 +1753,8 @@ public class RankingHelperTest extends UiServiceTestCase {
update.setBypassDnd(true);
mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, update, true, false);
- assertTrue(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false)
+ assertFalse(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false)
.canBypassDnd());
-
- // setup + 1st check
- verify(mPm, times(2)).getPackageInfoAsUser(any(), anyInt(), anyInt());
}
@Test
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 d02a983c2c9d..afc12636007f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -17,6 +17,9 @@
package com.android.server.notification;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertEquals;
@@ -569,8 +572,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
mZenModeHelperSpy.mConfig.allowMessages = true;
mZenModeHelperSpy.mConfig.allowEvents = true;
mZenModeHelperSpy.mConfig.allowRepeatCallers= true;
- mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
- mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("a", "a");
@@ -593,8 +594,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
mZenModeHelperSpy.mConfig.allowMessages = true;
mZenModeHelperSpy.mConfig.allowEvents = true;
mZenModeHelperSpy.mConfig.allowRepeatCallers= true;
- mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
- mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
mZenModeHelperSpy.mConfig.manualRule.zenMode =
@@ -645,6 +644,115 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
+ public void testMigrateSuppressedVisualEffects_oneExistsButOff() throws Exception {
+ String xml = "<zen version=\"6\" user=\"0\">\n"
+ + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
+ + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
+ + "visualScreenOff=\"false\" alarms=\"true\" "
+ + "media=\"true\" system=\"false\" />\n"
+ + "<disallow visualEffects=\"511\" />"
+ + "</zen>";
+
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml.getBytes())), null);
+ parser.nextTag();
+ mZenModeHelperSpy.readXml(parser, false);
+
+ assertEquals(0, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
+
+ xml = "<zen version=\"6\" user=\"0\">\n"
+ + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
+ + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
+ + "visualScreenOn=\"false\" alarms=\"true\" "
+ + "media=\"true\" system=\"false\" />\n"
+ + "<disallow visualEffects=\"511\" />"
+ + "</zen>";
+
+ parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml.getBytes())), null);
+ parser.nextTag();
+ mZenModeHelperSpy.readXml(parser, false);
+
+ assertEquals(0, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
+ }
+
+ @Test
+ public void testMigrateSuppressedVisualEffects_bothExistButOff() throws Exception {
+ String xml = "<zen version=\"6\" user=\"0\">\n"
+ + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
+ + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
+ + "visualScreenOff=\"false\" visualScreenOn=\"false\" alarms=\"true\" "
+ + "media=\"true\" system=\"false\" />\n"
+ + "<disallow visualEffects=\"511\" />"
+ + "</zen>";
+
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml.getBytes())), null);
+ parser.nextTag();
+ mZenModeHelperSpy.readXml(parser, false);
+
+ assertEquals(0, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
+ }
+
+ @Test
+ public void testMigrateSuppressedVisualEffects_bothExistButOn() throws Exception {
+ String xml = "<zen version=\"6\" user=\"0\">\n"
+ + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
+ + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
+ + "visualScreenOff=\"true\" visualScreenOn=\"true\" alarms=\"true\" "
+ + "media=\"true\" system=\"false\" />\n"
+ + "<disallow visualEffects=\"511\" />"
+ + "</zen>";
+
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml.getBytes())), null);
+ parser.nextTag();
+ mZenModeHelperSpy.readXml(parser, false);
+
+ assertEquals(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT
+ | SUPPRESSED_EFFECT_LIGHTS
+ | SUPPRESSED_EFFECT_PEEK,
+ mZenModeHelperSpy.mConfig.suppressedVisualEffects);
+
+ xml = "<zen version=\"6\" user=\"0\">\n"
+ + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
+ + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
+ + "visualScreenOff=\"false\" visualScreenOn=\"true\" alarms=\"true\" "
+ + "media=\"true\" system=\"false\" />\n"
+ + "<disallow visualEffects=\"511\" />"
+ + "</zen>";
+
+ parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml.getBytes())), null);
+ parser.nextTag();
+ mZenModeHelperSpy.readXml(parser, false);
+
+ assertEquals(SUPPRESSED_EFFECT_PEEK, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
+
+ xml = "<zen version=\"6\" user=\"0\">\n"
+ + "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
+ + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" "
+ + "visualScreenOff=\"true\" visualScreenOn=\"false\" alarms=\"true\" "
+ + "media=\"true\" system=\"false\" />\n"
+ + "<disallow visualEffects=\"511\" />"
+ + "</zen>";
+
+ parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml.getBytes())), null);
+ parser.nextTag();
+ mZenModeHelperSpy.readXml(parser, false);
+
+ assertEquals(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT | SUPPRESSED_EFFECT_LIGHTS,
+ mZenModeHelperSpy.mConfig.suppressedVisualEffects);
+ }
+
+ @Test
public void testReadXmlResetDefaultRules() throws Exception {
setupZenConfig();
@@ -705,16 +813,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
setupZenConfigMaintained();
}
- @Test
- public void testPolicyReadsSuppressedEffects() {
- mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
- mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
- mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
-
- NotificationManager.Policy policy = mZenModeHelperSpy.getNotificationPolicy();
- assertEquals(SUPPRESSED_EFFECT_BADGE, policy.suppressedVisualEffects);
- }
-
private void setupZenConfig() {
mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
mZenModeHelperSpy.mConfig.allowAlarms = false;
@@ -725,8 +823,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
mZenModeHelperSpy.mConfig.allowMessages = true;
mZenModeHelperSpy.mConfig.allowEvents = true;
mZenModeHelperSpy.mConfig.allowRepeatCallers= true;
- mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
- mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
mZenModeHelperSpy.mConfig.manualRule.zenMode =
@@ -746,8 +842,6 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertTrue(mZenModeHelperSpy.mConfig.allowMessages);
assertTrue(mZenModeHelperSpy.mConfig.allowEvents);
assertTrue(mZenModeHelperSpy.mConfig.allowRepeatCallers);
- assertTrue(mZenModeHelperSpy.mConfig.allowWhenScreenOff);
- assertTrue(mZenModeHelperSpy.mConfig.allowWhenScreenOn);
assertEquals(SUPPRESSED_EFFECT_BADGE, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
}
}
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 97c5ac911563..08b049669eab 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -192,6 +192,7 @@ public class AppStandbyController {
/** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */
static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11;
static final int MSG_REPORT_EXEMPTED_SYNC_START = 12;
+ static final int MSG_UPDATE_STABLE_CHARGING= 13;
long mCheckIdleIntervalMillis;
long mAppIdleParoleIntervalMillis;
@@ -213,10 +214,13 @@ public class AppStandbyController {
long mExemptedSyncAdapterTimeoutMillis;
/** Maximum time a system interaction should keep the buckets elevated. */
long mSystemInteractionTimeoutMillis;
+ /** The length of time phone must be charging before considered stable enough to run jobs */
+ long mStableChargingThresholdMillis;
volatile boolean mAppIdleEnabled;
boolean mAppIdleTempParoled;
boolean mCharging;
+ boolean mChargingStable;
private long mLastAppIdleParoledTime;
private boolean mSystemServicesReady = false;
// There was a system update, defaults need to be initialized after services are ready
@@ -297,7 +301,7 @@ public class AppStandbyController {
mPackageManager = mContext.getPackageManager();
mDeviceStateReceiver = new DeviceStateReceiver();
- IntentFilter deviceStates = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+ IntentFilter deviceStates = new IntentFilter(BatteryManager.ACTION_CHARGING);
deviceStates.addAction(BatteryManager.ACTION_DISCHARGING);
deviceStates.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
mContext.registerReceiver(mDeviceStateReceiver, deviceStates);
@@ -405,6 +409,27 @@ public class AppStandbyController {
synchronized (mAppIdleLock) {
if (mCharging != charging) {
mCharging = charging;
+ if (DEBUG) Slog.d(TAG, "Setting mCharging to " + charging);
+ if (charging) {
+ if (DEBUG) {
+ Slog.d(TAG, "Scheduling MSG_UPDATE_STABLE_CHARGING delay = "
+ + mStableChargingThresholdMillis);
+ }
+ mHandler.sendEmptyMessageDelayed(MSG_UPDATE_STABLE_CHARGING,
+ mStableChargingThresholdMillis);
+ } else {
+ mHandler.removeMessages(MSG_UPDATE_STABLE_CHARGING);
+ updateChargingStableState();
+ }
+ }
+ }
+ }
+
+ void updateChargingStableState() {
+ synchronized (mAppIdleLock) {
+ if (mChargingStable != mCharging) {
+ if (DEBUG) Slog.d(TAG, "Setting mChargingStable to " + mCharging);
+ mChargingStable = mCharging;
postParoleStateChanged();
}
}
@@ -431,7 +456,8 @@ public class AppStandbyController {
boolean isParoledOrCharging() {
if (!mAppIdleEnabled) return true;
synchronized (mAppIdleLock) {
- return mAppIdleTempParoled || mCharging;
+ // Only consider stable charging when determining charge state.
+ return mAppIdleTempParoled || mChargingStable;
}
}
@@ -1371,11 +1397,15 @@ public class AppStandbyController {
pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
pw.print(" mAppIdleTempParoled="); pw.print(mAppIdleTempParoled);
pw.print(" mCharging="); pw.print(mCharging);
+ pw.print(" mChargingStable="); pw.print(mChargingStable);
pw.print(" mLastAppIdleParoledTime=");
TimeUtils.formatDuration(mLastAppIdleParoledTime, pw);
pw.println();
pw.print("mScreenThresholds="); pw.println(Arrays.toString(mAppStandbyScreenThresholds));
pw.print("mElapsedThresholds="); pw.println(Arrays.toString(mAppStandbyElapsedThresholds));
+ pw.print("mStableChargingThresholdMillis=");
+ TimeUtils.formatDuration(mStableChargingThresholdMillis, pw);
+ pw.println();
}
/**
@@ -1549,7 +1579,7 @@ public class AppStandbyController {
case MSG_PAROLE_STATE_CHANGED:
if (DEBUG) Slog.d(TAG, "Parole state: " + mAppIdleTempParoled
- + ", Charging state:" + mCharging);
+ + ", Charging state:" + mChargingStable);
informParoleStateChanged();
break;
case MSG_CHECK_PACKAGE_IDLE_STATE:
@@ -1561,6 +1591,10 @@ public class AppStandbyController {
reportExemptedSyncStart((String) msg.obj, msg.arg1);
break;
+ case MSG_UPDATE_STABLE_CHARGING:
+ updateChargingStableState();
+ break;
+
default:
super.handleMessage(msg);
break;
@@ -1572,11 +1606,16 @@ public class AppStandbyController {
private class DeviceStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
- setChargingState(intent.getIntExtra("plugged", 0) != 0);
- } else if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
- onDeviceIdleModeChanged();
+ switch (intent.getAction()) {
+ case BatteryManager.ACTION_CHARGING:
+ setChargingState(true);
+ break;
+ case BatteryManager.ACTION_DISCHARGING:
+ setChargingState(false);
+ break;
+ case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED:
+ onDeviceIdleModeChanged();
+ break;
}
}
}
@@ -1620,9 +1659,11 @@ public class AppStandbyController {
*/
@Deprecated
private static final String KEY_IDLE_DURATION_OLD = "idle_duration";
-
+ @Deprecated
private static final String KEY_IDLE_DURATION = "idle_duration2";
+ @Deprecated
private static final String KEY_WALLCLOCK_THRESHOLD = "wallclock_threshold";
+
private static final String KEY_PAROLE_INTERVAL = "parole_interval";
private static final String KEY_PAROLE_WINDOW = "parole_window";
private static final String KEY_PAROLE_DURATION = "parole_duration";
@@ -1638,12 +1679,14 @@ public class AppStandbyController {
private static final String KEY_EXEMPTED_SYNC_HOLD_DURATION = "exempted_sync_duration";
private static final String KEY_SYSTEM_INTERACTION_HOLD_DURATION =
"system_interaction_duration";
+ private static final String KEY_STABLE_CHARGING_THRESHOLD = "stable_charging_threshold";
public static final long DEFAULT_STRONG_USAGE_TIMEOUT = 1 * ONE_HOUR;
public static final long DEFAULT_NOTIFICATION_TIMEOUT = 12 * ONE_HOUR;
public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT = 2 * ONE_HOUR;
public static final long DEFAULT_SYSTEM_INTERACTION_TIMEOUT = 10 * ONE_MINUTE;
public static final long DEFAULT_SYNC_ADAPTER_TIMEOUT = 10 * ONE_MINUTE;
public static final long DEFAULT_EXEMPTED_SYNC_TIMEOUT = 10 * ONE_MINUTE;
+ public static final long DEFAULT_STABLE_CHARGING_THRESHOLD = 10 * ONE_MINUTE;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -1733,6 +1776,9 @@ public class AppStandbyController {
mSystemInteractionTimeoutMillis = mParser.getDurationMillis
(KEY_SYSTEM_INTERACTION_HOLD_DURATION,
COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYSTEM_INTERACTION_TIMEOUT);
+ mStableChargingThresholdMillis = mParser.getDurationMillis
+ (KEY_STABLE_CHARGING_THRESHOLD,
+ COMPRESS_TIME ? ONE_MINUTE : DEFAULT_STABLE_CHARGING_THRESHOLD);
}
}
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index f1653ce6c2ae..f2438b833d90 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -2900,12 +2900,30 @@ public final class Telephony {
* @hide
*/
public static final int OWNED_BY_DPC = 0;
+
/**
* Possible value for the OWNED_BY field.
* APN is owned by other sources.
* @hide
*/
public static final int OWNED_BY_OTHERS = 1;
+
+ /**
+ * The APN set id. When the user manually selects an APN or the framework sets an APN as
+ * preferred, all APNs with the same set id as the selected APN should be prioritized over
+ * APNs in other sets.
+ * @hide
+ */
+ public static final String APN_SET_ID = "apn_set_id";
+
+ /**
+ * Possible value for the APN_SET_ID field. By default APNs will not belong to a set. If the
+ * user manually selects an APN with no set set, there is no need to prioritize any specific
+ * APN set ids.
+ * @hide
+ */
+ public static final int NO_SET_SET = 0;
+
}
/**
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 006d7ab96c73..c2e779e3fa32 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -444,7 +444,7 @@ public class PhoneStateListener {
* Callback invoked when device call state changes.
* @param state call state
* @param phoneNumber call phone number. If application does not have
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} permission or carrier
+ * {@link android.Manifest.permission#READ_CALL_LOG READ_CALL_LOG} permission or carrier
* privileges (see {@link TelephonyManager#hasCarrierPrivileges}), an empty string will be
* passed as an argument.
*
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 01fb29923061..5a77a9f2d3ff 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -334,10 +334,12 @@ public class TelephonyManager {
*
* <p>
* The {@link #EXTRA_STATE} extra indicates the new call state.
- * If the new state is RINGING, a second extra
- * {@link #EXTRA_INCOMING_NUMBER} provides the incoming phone number as
- * a String.
- *
+ * If a receiving app has {@link android.Manifest.permission#READ_CALL_LOG} permission, a second
+ * extra {@link #EXTRA_INCOMING_NUMBER} provides the phone number for incoming and outoing calls
+ * as a String. Note: If the receiving app has
+ * {@link android.Manifest.permission#READ_CALL_LOG} and
+ * {@link android.Manifest.permission#READ_PHONE_STATE} permission, it will receive the
+ * broadcast twice; one with the phone number and another without it.
* <p class="note">
* This was a {@link android.content.Context#sendStickyBroadcast sticky}
* broadcast in version 1.0, but it is no longer sticky.
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
index 1dda6bf2b8bc..90e9880bd03e 100644
--- a/telephony/java/com/android/ims/ImsConfig.java
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -35,7 +35,6 @@ public class ImsConfig {
private static final String TAG = "ImsConfig";
private boolean DBG = true;
private final IImsConfig miConfig;
- private Context mContext;
/**
* Broadcast action: the feature enable status was changed
@@ -541,14 +540,12 @@ public class ImsConfig {
public static final int WIFI_PREFERRED = 2;
}
- public ImsConfig(IImsConfig iconfig, Context context) {
- if (DBG) Rlog.d(TAG, "ImsConfig created");
+ public ImsConfig(IImsConfig iconfig) {
miConfig = iconfig;
- mContext = context;
}
/**
- * @deprecated see {@link #getInt(int)} instead.
+ * @deprecated see {@link #getConfigInt(int)} instead.
*/
public int getProvisionedValue(int item) throws ImsException {
return getConfigInt(item);
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index a182f2be421f..bbe38b7f709a 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -15,6 +15,9 @@
*/
package com.android.internal.telephony;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import android.Manifest;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -75,7 +78,7 @@ public final class TelephonyPermissions {
/**
* Check whether the app with the given pid/uid can read phone state.
*
- * <p>This method behaves in one of the following ways:
+ * <p>This method behaves in one of the following ways:
* <ul>
* <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the
* READ_PHONE_STATE runtime permission, or carrier privileges on the given subId.
@@ -132,6 +135,40 @@ public final class TelephonyPermissions {
}
/**
+ * Check whether the app with the given pid/uid can read the call log.
+ * @return {@code true} if the specified app has the read call log permission and AppOpp granted
+ * to it, {@code false} otherwise.
+ */
+ public static boolean checkReadCallLog(
+ Context context, int subId, int pid, int uid, String callingPackage) {
+ return checkReadCallLog(
+ context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage);
+ }
+
+ @VisibleForTesting
+ public static boolean checkReadCallLog(
+ Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
+ String callingPackage) {
+
+ if (context.checkPermission(Manifest.permission.READ_CALL_LOG, pid, uid)
+ != PERMISSION_GRANTED) {
+ // If we don't have the runtime permission, but do have carrier privileges, that
+ // suffices for being able to see the call phone numbers.
+ if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ enforceCarrierPrivilege(telephonySupplier, subId, uid, "readCallLog");
+ return true;
+ }
+ return false;
+ }
+
+ // We have READ_CALL_LOG permission, so return true as long as the AppOps bit hasn't been
+ // revoked.
+ AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ return appOps.noteOp(AppOpsManager.OP_READ_CALL_LOG, uid, callingPackage) ==
+ AppOpsManager.MODE_ALLOWED;
+ }
+
+ /**
* Returns whether the caller can read phone numbers.
*
* <p>Besides apps with the ability to read phone state per {@link #checkReadPhoneState}, the
@@ -204,7 +241,7 @@ public final class TelephonyPermissions {
public static void enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
Context context, int subId, String message) {
if (context.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE) ==
- PackageManager.PERMISSION_GRANTED) {
+ PERMISSION_GRANTED) {
return;
}
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 4dfd0507f351..9d260ebf7231 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -364,6 +364,13 @@ public class MockContext extends Context {
}
/** @hide */
+ @Override
+ public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
+ String[] receiverPermissions) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** @hide */
@SystemApi
@Override
public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 4ca175feaff2..6ce66f0f4546 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -98,7 +98,7 @@ public class AppLaunch extends InstrumentationTestCase {
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,binder_driver,hal";
+ "sched,freq,gfx,view,dalvik,webview,input,wm,disk,am,wm,binder_driver,hal,ss";
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";
diff --git a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
index fc46b9c85980..788924b1d3bf 100644
--- a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
+++ b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
@@ -116,20 +116,6 @@ public class NetworkStatsFactoryTest {
}
@Test
- public void testNetworkStatsSummary() throws Exception {
- stageFile(R.raw.net_dev_typical, file("net/dev"));
-
- final NetworkStats stats = mFactory.readNetworkStatsIfaceDev();
- assertEquals(6, stats.size());
- assertStatsEntry(stats, "lo", UID_ALL, SET_ALL, TAG_NONE, 8308L, 8308L);
- assertStatsEntry(stats, "rmnet0", UID_ALL, SET_ALL, TAG_NONE, 1507570L, 489339L);
- assertStatsEntry(stats, "ifb0", UID_ALL, SET_ALL, TAG_NONE, 52454L, 0L);
- assertStatsEntry(stats, "ifb1", UID_ALL, SET_ALL, TAG_NONE, 52454L, 0L);
- assertStatsEntry(stats, "sit0", UID_ALL, SET_ALL, TAG_NONE, 0L, 0L);
- assertStatsEntry(stats, "ip6tnl0", UID_ALL, SET_ALL, TAG_NONE, 0L, 0L);
- }
-
- @Test
public void testNetworkStatsSingle() throws Exception {
stageFile(R.raw.xt_qtaguid_iface_typical, file("net/xt_qtaguid/iface_stat_all"));
diff --git a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
index 21662407db42..25bd7c06be49 100644
--- a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
+++ b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
@@ -175,6 +175,12 @@ public class BroadcastInterceptingContext extends ContextWrapper {
}
@Override
+ public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
+ String[] receiverPermissions) {
+ sendBroadcast(intent);
+ }
+
+ @Override
public void sendBroadcastAsUser(Intent intent, UserHandle user) {
sendBroadcast(intent);
}
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 19c6c3107e7c..7f48544c0ae4 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -598,10 +598,13 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
// If no inner element exists, represent a unique identifier
out_resource->value = util::make_unique<Id>();
} else {
- // If an inner element exists, the inner element must be a reference to
- // another resource id
Reference* ref = ValueCast<Reference>(out_resource->value.get());
- if (!ref || ref->name.value().type != ResourceType::kId) {
+ if (ref && !ref->name && !ref->id) {
+ // A null reference also means there is no inner element when ids are in the form:
+ // <id name="name"/>
+ out_resource->value = util::make_unique<Id>();
+ } else if (!ref || ref->name.value().type != ResourceType::kId) {
+ // If an inner element exists, the inner element must be a reference to another resource id
diag_->Error(DiagMessage(out_resource->source)
<< "<" << parser->element_name()
<< "> inner element must either be a resource reference or empty");
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index c12b9fac5704..41b4041efb7a 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -944,20 +944,30 @@ TEST_F(ResourceParserTest, ParseIdItem) {
ASSERT_THAT(test::GetValue<Id>(&table_, "id/bar"), NotNull());
ASSERT_THAT(test::GetValue<Id>(&table_, "id/baz"), NotNull());
+ input = R"(
+ <id name="foo2">@id/bar</id>
+ <id name="bar2"/>
+ <id name="baz2"></id>)";
+ ASSERT_TRUE(TestParse(input));
+
+ ASSERT_THAT(test::GetValue<Reference>(&table_, "id/foo2"), NotNull());
+ ASSERT_THAT(test::GetValue<Id>(&table_, "id/bar2"), NotNull());
+ ASSERT_THAT(test::GetValue<Id>(&table_, "id/baz2"), NotNull());
+
// Reject attribute references
- input = R"(<item name="foo2" type="id">?attr/bar"</item>)";
+ input = R"(<item name="foo3" type="id">?attr/bar"</item>)";
ASSERT_FALSE(TestParse(input));
// Reject non-references
- input = R"(<item name="foo3" type="id">0x7f010001</item>)";
+ input = R"(<item name="foo4" type="id">0x7f010001</item>)";
ASSERT_FALSE(TestParse(input));
- input = R"(<item name="foo4" type="id">@drawable/my_image</item>)";
+ input = R"(<item name="foo5" type="id">@drawable/my_image</item>)";
ASSERT_FALSE(TestParse(input));
- input = R"(<item name="foo5" type="id"><string name="biz"></string></item>)";
+ input = R"(<item name="foo6" type="id"><string name="biz"></string></item>)";
ASSERT_FALSE(TestParse(input));
// Ids that reference other resource ids cannot be public
- input = R"(<public name="foo6" type="id">@id/bar6</item>)";
+ input = R"(<public name="foo7" type="id">@id/bar7</item>)";
ASSERT_FALSE(TestParse(input));
}
diff --git a/tools/aapt2/format/binary/XmlFlattener.cpp b/tools/aapt2/format/binary/XmlFlattener.cpp
index d897941da6c4..2fe24245f3d9 100644
--- a/tools/aapt2/format/binary/XmlFlattener.cpp
+++ b/tools/aapt2/format/binary/XmlFlattener.cpp
@@ -79,23 +79,31 @@ class XmlFlattenerVisitor : public xml::ConstVisitor {
}
void Visit(const xml::Text* node) override {
- if (util::TrimWhitespace(node->text).empty()) {
- // Skip whitespace only text nodes.
+ std::string text = util::TrimWhitespace(node->text).to_string();
+
+ // Skip whitespace only text nodes.
+ if (text.empty()) {
return;
}
+ // Compact leading and trailing whitespace into a single space
+ if (isspace(node->text[0])) {
+ text = ' ' + text;
+ }
+ if (isspace(node->text[node->text.length() - 1])) {
+ text = text + ' ';
+ }
+
ChunkWriter writer(buffer_);
ResXMLTree_node* flat_node = writer.StartChunk<ResXMLTree_node>(RES_XML_CDATA_TYPE);
flat_node->lineNumber = util::HostToDevice32(node->line_number);
flat_node->comment.index = util::HostToDevice32(-1);
- ResXMLTree_cdataExt* flat_text = writer.NextBlock<ResXMLTree_cdataExt>();
-
// Process plain strings to make sure they get properly escaped.
- StringBuilder builder;
- builder.AppendText(node->text);
- AddString(builder.to_string(), kLowPriority, &flat_text->data);
+ text = StringBuilder(true /*preserve_spaces*/).AppendText(text).to_string();
+ ResXMLTree_cdataExt* flat_text = writer.NextBlock<ResXMLTree_cdataExt>();
+ AddString(text, kLowPriority, &flat_text->data);
writer.Finish();
}
diff --git a/tools/aapt2/format/binary/XmlFlattener_test.cpp b/tools/aapt2/format/binary/XmlFlattener_test.cpp
index 08243feb3769..25786b1659e7 100644
--- a/tools/aapt2/format/binary/XmlFlattener_test.cpp
+++ b/tools/aapt2/format/binary/XmlFlattener_test.cpp
@@ -286,6 +286,165 @@ TEST_F(XmlFlattenerTest, ProcessEscapedStrings) {
EXPECT_THAT(tree.getText(&len), StrEq(u"\\d{5}"));
}
+TEST_F(XmlFlattenerTest, ProcessQuotes) {
+ std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(
+ R"(<root>
+ <item>Regular text</item>
+ <item>"Text in double quotes"</item>
+ <item>'Text in single quotes'</item>
+ <item>Text containing "double quotes"</item>
+ <item>Text containing 'single quotes'</item>
+ </root>)");
+
+ size_t len;
+ android::ResXMLTree tree;
+
+ XmlFlattenerOptions options;
+ ASSERT_TRUE(Flatten(doc.get(), &tree, options));
+
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
+ EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
+ EXPECT_THAT(tree.getText(&len), StrEq(u"Regular text"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
+
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
+ EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
+ EXPECT_THAT(tree.getText(&len), StrEq(u"\"Text in double quotes\""));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
+
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
+ EXPECT_THAT(tree.getElementNamespace(&len), IsNull());
+ EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
+ EXPECT_THAT(tree.getText(&len), StrEq(u"'Text in single quotes'"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
+
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
+ EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
+ EXPECT_THAT(tree.getText(&len), StrEq(u"Text containing \"double quotes\""));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
+
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
+ EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
+ EXPECT_THAT(tree.getText(&len), StrEq(u"Text containing 'single quotes'"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
+
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_DOCUMENT));
+}
+
+TEST_F(XmlFlattenerTest, ProcessWhitepspace) {
+ std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(
+ R"(<root>
+ <item> Compact Spaces </item>
+ <item>
+ A
+ </item>
+ <item>B </item>
+ <item>C </item>
+ <item> D </item>
+ <item> E</item>
+ <item> F</item>
+ <item> G </item>
+ <item> H </item>
+<item>
+I
+</item>
+<item>
+
+ J
+
+</item>
+ <item>
+ </item>
+ </root>)");
+
+ size_t len;
+ android::ResXMLTree tree;
+
+ XmlFlattenerOptions options;
+ ASSERT_TRUE(Flatten(doc.get(), &tree, options));
+
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
+ EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
+ EXPECT_THAT(tree.getText(&len), StrEq(u" Compact Spaces "));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
+
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
+ EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
+ EXPECT_THAT(tree.getText(&len), StrEq(u" A "));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
+
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
+ EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
+ EXPECT_THAT(tree.getText(&len), StrEq(u"B "));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
+
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
+ EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
+ EXPECT_THAT(tree.getText(&len), StrEq(u"C "));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
+
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
+ EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
+ EXPECT_THAT(tree.getText(&len), StrEq(u" D "));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
+
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
+ EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
+ EXPECT_THAT(tree.getText(&len), StrEq(u" E"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
+
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
+ EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
+ EXPECT_THAT(tree.getText(&len), StrEq(u" F"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
+
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
+ EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
+ EXPECT_THAT(tree.getText(&len), StrEq(u" G "));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
+
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
+ EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
+ EXPECT_THAT(tree.getText(&len), StrEq(u" H "));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
+
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
+ EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
+ EXPECT_THAT(tree.getText(&len), StrEq(u" I "));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
+
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
+ EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
+ EXPECT_THAT(tree.getText(&len), StrEq(u" J "));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
+
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
+ EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
+
+ ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_DOCUMENT));
+}
+
TEST_F(XmlFlattenerTest, FlattenRawValueOnlyMakesCompiledValueToo) {
std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<element foo="bar" />)");
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index a274a8c7bf9a..3f9588acf827 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -413,7 +413,8 @@ static bool generateSectionListCpp(Descriptor const* descriptor) {
case SECTION_NONE:
continue;
case SECTION_FILE:
- printf(" new FileSection(%d, \"%s\"),\n", field->number(), s.args().c_str());
+ printf(" new FileSection(%d, \"%s\", %s),\n", field->number(), s.args().c_str(),
+ s.device_specific() ? "true" : "false");
break;
case SECTION_COMMAND:
printf(" new CommandSection(%d,", field->number());